v0.2:重写项目。 #6
| @@ -1,189 +1,100 @@ | |||||||
| use std::{ | use std::sync::{Arc, Mutex, MutexGuard}; | ||||||
|     sync::{ |  | ||||||
|         Arc, Mutex, MutexGuard, |  | ||||||
|     }, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| use embedded_hal::digital::v2::{OutputPin, PinState}; | use embedded_hal::digital::v2::{OutputPin, PinState}; | ||||||
| use embedded_svc::event_bus::{EventBus, Postbox}; | 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::{ | use esp_idf_svc::eventloop::{ | ||||||
|     Background, EspBackgroundEventLoop, EspEventFetchData, EspEventLoop, EspEventPostData, |     Background, EspBackgroundEventLoop, EspEventFetchData, EspEventLoop, EspEventPostData, | ||||||
|     EspSubscription, EspTypedEventDeserializer, EspTypedEventSerializer, EspTypedEventSource, User, |     EspSubscription, EspTypedEventDeserializer, EspTypedEventSerializer, EspTypedEventSource, User, | ||||||
| }; | }; | ||||||
| use esp_idf_sys::c_types; | use esp_idf_sys::c_types; | ||||||
| use log::{info, warn, debug}; | use log::{warn}; | ||||||
| use serde_json::json; | use serde_json::json; | ||||||
|  |  | ||||||
| use crate::voltage_detection::{VoltageDetectionWorker, VOLTAGE_EVENTLOOP}; | use crate::voltage_detection::{VoltageDetectionWorker, VOLTAGE_EVENTLOOP}; | ||||||
|  |  | ||||||
| const WAITING_OFF_SECONDS: u8 = 60; | pub static mut CHARGE_STATE_EVENT_LOOP: Option< | ||||||
|  |  | ||||||
| pub static mut DC_OUT_STATE_EVENT_LOOP: Option< |  | ||||||
|     EspEventLoop<esp_idf_svc::eventloop::User<Background>>, |     EspEventLoop<esp_idf_svc::eventloop::User<Background>>, | ||||||
| > = None; | > = None; | ||||||
|  |  | ||||||
| #[derive(Debug, Clone, Copy, PartialEq)] | #[derive(Debug, Clone, Copy, PartialEq)] | ||||||
| pub enum DcOutStatus { | pub enum ChargeStatus { | ||||||
|     WaitingOn(u8), |     Charging, | ||||||
|     On, |     Charged, | ||||||
|     Off, |  | ||||||
|     WaitingOff, |  | ||||||
|     TurningOff(u8), |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Clone, Copy)] | #[derive(Debug, Clone, Copy)] | ||||||
| pub struct DcOutControllerState { | pub struct ChargeControllerState { | ||||||
|     pub status: DcOutStatus, |     pub status: ChargeStatus, | ||||||
|     pub pin_state: PinState, |     pub pin_state: PinState, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl DcOutControllerState { | impl ChargeControllerState { | ||||||
|     pub fn new() -> Self { |     pub fn new() -> Self { | ||||||
|         Self { |         Self { | ||||||
|             status: DcOutStatus::On, |             status: ChargeStatus::Charging, | ||||||
|             pin_state: PinState::Low, |             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 { |     pub fn to_json(&self) -> String { | ||||||
|         let status = match self.status { |         let status = match self.status { | ||||||
|             DcOutStatus::WaitingOn(_) => "WaitingOn", |             ChargeStatus::Charging => "Charging", | ||||||
|             DcOutStatus::On => "On", |             ChargeStatus::Charged => "Charged", | ||||||
|             DcOutStatus::Off => "Off", |  | ||||||
|             DcOutStatus::WaitingOff => "WaitingOff", |  | ||||||
|             DcOutStatus::TurningOff(_) => "TurningOff", |  | ||||||
|         }; |         }; | ||||||
|         let pin_state = match self.pin_state { |         let pin_state = match self.pin_state { | ||||||
|             PinState::Low => "Low", |             PinState::Low => "Low", | ||||||
|             PinState::High => "High", |             PinState::High => "High", | ||||||
|         }; |         }; | ||||||
|         let seconds: i16 = match self.status { |         json!({ "status": status, "pin_state": pin_state}).to_string() | ||||||
|             DcOutStatus::WaitingOn(seconds) => seconds.into(), |  | ||||||
|             DcOutStatus::TurningOff(seconds) => seconds.into(), |  | ||||||
|             _ => -1, |  | ||||||
|         }; |  | ||||||
|         json!({ "status": status, "pin_state": pin_state, "seconds": seconds }).to_string() |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl EspTypedEventSource for DcOutControllerState { | impl EspTypedEventSource for ChargeControllerState { | ||||||
|     fn source() -> *const c_types::c_char { |     fn source() -> *const c_types::c_char { | ||||||
|         b"Charge\0".as_ptr() as *const _ |         b"Charge\0".as_ptr() as *const _ | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl EspTypedEventSerializer<DcOutControllerState> for DcOutControllerState { | impl EspTypedEventSerializer<ChargeControllerState> for ChargeControllerState { | ||||||
|     fn serialize<R>( |     fn serialize<R>( | ||||||
|         event: &DcOutControllerState, |         event: &ChargeControllerState, | ||||||
|         f: impl for<'a> FnOnce(&'a EspEventPostData) -> R, |         f: impl for<'a> FnOnce(&'a EspEventPostData) -> R, | ||||||
|     ) -> R { |     ) -> R { | ||||||
|         f(&unsafe { EspEventPostData::new(Self::source(), Self::event_id(), event) }) |         f(&unsafe { EspEventPostData::new(Self::source(), Self::event_id(), event) }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl EspTypedEventDeserializer<DcOutControllerState> for DcOutControllerState { | impl EspTypedEventDeserializer<ChargeControllerState> for ChargeControllerState { | ||||||
|     fn deserialize<R>( |     fn deserialize<R>( | ||||||
|         data: &EspEventFetchData, |         data: &EspEventFetchData, | ||||||
|         f: &mut impl for<'a> FnMut(&'a DcOutControllerState) -> R, |         f: &mut impl for<'a> FnMut(&'a ChargeControllerState) -> R, | ||||||
|     ) -> R { |     ) -> R { | ||||||
|         f(unsafe { data.as_payload() }) |         f(unsafe { data.as_payload() }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| type DcOutPin = Gpio6<Output>; | type ChargeCtlPin = Gpio7<Output>; | ||||||
|  |  | ||||||
| pub struct DcOutController { | pub struct ChargeController { | ||||||
|     pub state: DcOutControllerState, |     pub state: ChargeControllerState, | ||||||
|     voltage_subscription: Option<EspSubscription<User<Background>>>, |     voltage_subscription: Option<EspSubscription<User<Background>>>, | ||||||
|     pin: Arc<Mutex<DcOutPin>>, |     pin: Arc<Mutex<ChargeCtlPin>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl DcOutController { | impl ChargeController { | ||||||
|     pub fn new() -> anyhow::Result<Self> { |     pub fn new() -> anyhow::Result<Self> { | ||||||
|         let pin = unsafe { Gpio6::<Output>::new() } |         let pin = unsafe { Gpio7::<Output>::new() } | ||||||
|             .into_output() |             .into_output() | ||||||
|             .map_err(|err| anyhow::anyhow!("Make Gpio6 Into output Failed. {}", err))?; |             .map_err(|err| anyhow::anyhow!("Make Gpio6 Into output Failed. {}", err))?; | ||||||
|  |  | ||||||
|         match EspBackgroundEventLoop::new(&Default::default()) { |         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), |             Err(err) => anyhow::bail!("Init Event Loop failed. {:?}", err), | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         anyhow::Ok(Self { |         anyhow::Ok(Self { | ||||||
|             state: DcOutControllerState::new(), |             state: ChargeControllerState::new(), | ||||||
|             voltage_subscription: None, |             voltage_subscription: None, | ||||||
|             pin: Arc::new(Mutex::new(pin)), |             pin: Arc::new(Mutex::new(pin)), | ||||||
|         }) |         }) | ||||||
| @@ -196,33 +107,39 @@ impl DcOutController { | |||||||
|         if let Some(event_loop) = unsafe { VOLTAGE_EVENTLOOP.as_mut() } { |         if let Some(event_loop) = unsafe { VOLTAGE_EVENTLOOP.as_mut() } { | ||||||
|             let voltage_subscription = event_loop |             let voltage_subscription = event_loop | ||||||
|                 .subscribe(move |obj: &VoltageDetectionWorker| { |                 .subscribe(move |obj: &VoltageDetectionWorker| { | ||||||
|                     if obj.adapter_voltage < 1000 { |                     match state.status { | ||||||
|                         if obj.battery_voltage < 1000 { |                         ChargeStatus::Charging => { | ||||||
|                             state.turn_off(); |                             if obj.battery_voltage < 12600 { | ||||||
|                         } else { |                                 state.status = ChargeStatus::Charging; | ||||||
|                             state.handle_adapter_down(); |                             } 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() { |                     match pin.lock() { | ||||||
|                         Ok(pin) => { |                         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); |                                 warn!("Put Control Pin State Failed. {}", err); | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                         Err(_) => todo!(), |                         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) { |                         if let Err(err) = event_loop.post(&state, None) { | ||||||
|                             warn!("Post DC Out Status Failed. {}", err); |                             warn!("Post DC Out Status Failed. {}", err); | ||||||
|                         } |                         } | ||||||
|                     } else { |                     } 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))?; |                 .map_err(|err| anyhow::anyhow!("Subscribe Voltage Failed. {}", err))?; | ||||||
|             self.voltage_subscription = Some(voltage_subscription); |             self.voltage_subscription = Some(voltage_subscription); | ||||||
| @@ -232,14 +149,14 @@ impl DcOutController { | |||||||
|         anyhow::Ok(()) |         anyhow::Ok(()) | ||||||
|     } |     } | ||||||
|     fn output_ctl( |     fn output_ctl( | ||||||
|         mut state: DcOutControllerState, |         state: &mut ChargeControllerState, | ||||||
|         mut pin: MutexGuard<DcOutPin>, |         mut pin: MutexGuard<ChargeCtlPin>, | ||||||
|     ) -> anyhow::Result<()> { |     ) -> anyhow::Result<()> { | ||||||
|         if DcOutStatus::Off == state.status && state.pin_state == PinState::Low { |         if ChargeStatus::Charging == state.status { | ||||||
|             pin.set_high() |             pin.set_high() | ||||||
|                 .map_err(|err| anyhow::anyhow!("Set DC Output Control Pin High Failed. {}", err))?; |                 .map_err(|err| anyhow::anyhow!("Set DC Output Control Pin High Failed. {}", err))?; | ||||||
|             state.pin_state = PinState::High; |             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() |             pin.set_low() | ||||||
|                 .map_err(|err| anyhow::anyhow!("Set DC Output Control Pin Low Failed. {}", err))?; |                 .map_err(|err| anyhow::anyhow!("Set DC Output Control Pin Low Failed. {}", err))?; | ||||||
|             state.pin_state = PinState::Low; |             state.pin_state = PinState::Low; | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								src/main.rs
									
									
									
									
									
								
							| @@ -15,12 +15,13 @@ mod message_queue; | |||||||
| mod time; | mod time; | ||||||
| mod voltage_detection; | mod voltage_detection; | ||||||
| mod wifi; | mod wifi; | ||||||
|  | mod charge_controller; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|     beep::{ringtone, Beep}, |     beep::{ringtone, Beep}, | ||||||
|     dc_out_controller::{DcOutController, DcOutControllerState, DC_OUT_STATE_EVENT_LOOP}, |     dc_out_controller::{DcOutController, DcOutControllerState, DC_OUT_STATE_EVENT_LOOP}, | ||||||
|     message_queue::MqDto, |     message_queue::MqDto, | ||||||
|     voltage_detection::{VoltageDetectionWorker, VOLTAGE_EVENTLOOP}, |     voltage_detection::{VoltageDetectionWorker, VOLTAGE_EVENTLOOP}, charge_controller::{CHARGE_STATE_EVENT_LOOP, ChargeControllerState, ChargeController}, | ||||||
| }; | }; | ||||||
| use crate::{ | use crate::{ | ||||||
|     message_queue::MessageQueue, time::Time, voltage_detection::VoltageDetection, wifi::Internet, |     message_queue::MessageQueue, time::Time, voltage_detection::VoltageDetection, wifi::Internet, | ||||||
| @@ -56,7 +57,7 @@ fn main() { | |||||||
|         blink.play(); |         blink.play(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     let mut voltage_detection = VoltageDetection::new(); |     let voltage_detection = VoltageDetection::new(); | ||||||
|  |  | ||||||
|     voltage_detection.unwrap() |     voltage_detection.unwrap() | ||||||
|         .watching() |         .watching() | ||||||
| @@ -77,6 +78,12 @@ fn main() { | |||||||
|         .watch() |         .watch() | ||||||
|         .expect("Can not watch for dc_out_controller"); |         .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)); |     sleep(Duration::from_millis(100)); | ||||||
|  |  | ||||||
|     let mut _mq = MessageQueue::new(); |     let mut _mq = MessageQueue::new(); | ||||||
| @@ -91,6 +98,7 @@ fn main() { | |||||||
|  |  | ||||||
|     let _mq_tx_for_voltage = _mq.tx.clone(); |     let _mq_tx_for_voltage = _mq.tx.clone(); | ||||||
|     let _mq_tx_for_dc_out_state = _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; |     let _voltage_subscription; | ||||||
|     if let Some(voltage_event_loop) = unsafe { VOLTAGE_EVENTLOOP.as_mut() } { |     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!"); |         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 { |     loop { | ||||||
|         sleep(Duration::from_millis(100)); |         sleep(Duration::from_millis(100)); | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user