diff --git a/gem-remotes-esp32/src/commands.rs b/gem-remotes-esp32/src/commands.rs index 42fbe80..0a1e24d 100644 --- a/gem-remotes-esp32/src/commands.rs +++ b/gem-remotes-esp32/src/commands.rs @@ -23,6 +23,10 @@ pub enum Commands { ButtonTimerExpired, ButtonTimerRestart, ButtonTimerClear, + + NotifyMotorUp, + NotifyMotorDown, + NotifyMotorStop, } pub type CmdType = std::mem::Discriminant; diff --git a/gem-remotes-esp32/src/main.rs b/gem-remotes-esp32/src/main.rs index 735277e..756f51b 100644 --- a/gem-remotes-esp32/src/main.rs +++ b/gem-remotes-esp32/src/main.rs @@ -10,7 +10,6 @@ use log::*; //{trace, debug, info, warn, error} use anyhow::Result; use async_executor::Executor; use futures_lite::future; -use std::boxed::Box; // Debug modules mod test_console; @@ -38,35 +37,23 @@ fn main() { //log::set_max_level(log::LevelFilter::Info); match future::block_on(main_loop()) { - Ok(_) => {error!("Exited main loop normally, but this should be impossible.")} - Err(e) => {error!("Exited main loop with error {}", e)} + Ok(_) => {error!("Exited main loop with no errors, but this should not happen."); panic!();} + Err(e) => {error!("Exited main loop with error {}", e); panic!();} }; - //TODO: can we restart the microcontroller here? } -/* -async fn test_loop() -> Result<()> { - let timer_service = EspTaskTimerService::new()?; - - let mut async_timer = timer_service.timer_async()?; - loop { - async_timer.after(Duration::from_secs(5)).await?; - debug!("Tick "); - } -} */ - async fn main_loop() -> Result<()> { info!("Entering main loop"); // Create dispatch early so it can outlive most other things let mut dp = dispatch::Dispatch::new(); - // Debug Drivers - let motor_driver = Box::new(motor_driver::MotorDriverDebug {}); + // Debug Drivers (TODO: remove debug) + let motor_driver = motor_driver::MotorDriverDebug::new(dp.get_cmd_channel()); // Setup of various drivers that need to out-live the executor let m_chan = motor_controller::Controller::prepare_controller(&mut dp); - let mut motor_control = motor_controller::Controller::new(m_chan, dp.get_cmd_channel(), motor_driver); + let mut motor_control = motor_controller::Controller::new(m_chan, dp.get_cmd_channel(), motor_driver.get_endpoint()); // Setup callback timers let mut button_timer = MessageTimer::::new_on_dispatch( Commands::ButtonTimerRestart, @@ -85,7 +72,7 @@ async fn main_loop() -> Result<()> { let executor = Executor::new(); let mut tasks:Vec<_> = Vec::new(); - //Queue Up debug tasks (TODO: remove) + //Queue Up debug tasks (TODO: remove debug) let cli_endpoint = dp.get_cmd_channel(); tasks.push(executor.spawn(test_console::start_cli(cli_endpoint))); //tasks.push(executor.spawn(test_loop())); @@ -97,6 +84,7 @@ async fn main_loop() -> Result<()> { tasks.push(executor.spawn(button_timer.run())); tasks.push(executor.spawn(stopping_timer.run())); tasks.push(executor.spawn(ble_server.run())); + tasks.push(executor.spawn(motor_driver.run())); tasks.push(executor.spawn(dp.cmd_loop())); //Once we have all our tasks, await on them all to run them in parallel. @@ -107,4 +95,6 @@ async fn main_loop() -> Result<()> { info!("exiting main loop"); Ok(()) } - \ No newline at end of file + + + //TODO: check many of these mut functions to see if they don't need to be. \ No newline at end of file diff --git a/gem-remotes-esp32/src/motor_controller.rs b/gem-remotes-esp32/src/motor_controller.rs index 5b42643..e89a9fc 100644 --- a/gem-remotes-esp32/src/motor_controller.rs +++ b/gem-remotes-esp32/src/motor_controller.rs @@ -4,10 +4,10 @@ use log::*; //{trace, debug, info, warn, error} //use async_channel::Receiver; use anyhow::Result; -use std::boxed::Box; use crate::commands::Commands; -use crate::motor_driver::MotorDriver; +use crate::motor_driver::Commands as MotorCommands; +use crate::motor_driver::SendQ as MotorSendQ; use crate::dispatch::{Dispatch, RecvQ, SendQ}; #[derive(Debug, PartialEq, Clone)] @@ -23,16 +23,16 @@ pub struct Controller { state: ControllerStates, recv: RecvQ, send: SendQ, - driver: Box, + motor_q: MotorSendQ } impl Controller { - pub fn new(recv: RecvQ, send: SendQ, driver: Box) -> Controller { + pub fn new(recv: RecvQ, send: SendQ, motor_q: MotorSendQ) -> Controller { Controller { state: ControllerStates::Stopping, recv: recv, send: send, - driver: driver} + motor_q: motor_q} } /// Tell the message dispatch which messages we are interested in receiving, and get @@ -56,15 +56,15 @@ impl Controller { ControllerStates::Stopped => {} ControllerStates::Stopping => { self.send.send(Commands::StopTimerRestart).await?; - self.driver.stop()?; + self.motor_q.send(MotorCommands::Stop).await?; } ControllerStates::GoingUp => { self.send.send(Commands::ButtonTimerRestart).await?; - self.driver.start_up()?; + self.motor_q.send(MotorCommands::StartUp).await?; } ControllerStates::GoingDown => { self.send.send(Commands::ButtonTimerRestart).await?; - self.driver.start_down()?; + self.motor_q.send(MotorCommands::StartDown).await?; } } Ok(()) diff --git a/gem-remotes-esp32/src/motor_driver.rs b/gem-remotes-esp32/src/motor_driver.rs index 2897690..c54648d 100644 --- a/gem-remotes-esp32/src/motor_driver.rs +++ b/gem-remotes-esp32/src/motor_driver.rs @@ -2,28 +2,85 @@ use log::*; //{trace, debug, info, warn, error} use anyhow::Result; +use async_channel::{unbounded, Receiver, Sender}; +use std::panic; -pub trait MotorDriver: Send + Sync { - fn start_up(&mut self) -> Result<()>; - fn start_down(&mut self) -> Result<()>; - fn stop(&mut self) -> Result<()>; +use crate::dispatch; +use crate::commands::Commands as Dispatch_Commands; + +#[derive(Clone, Copy, Debug)] +pub enum Commands { + StartUp, + StartDown, + Stop } -pub struct MotorDriverDebug {} +pub type SendQ = Sender; +pub type RecvQ = Receiver; -impl MotorDriver for MotorDriverDebug { - fn start_up(&mut self) -> Result<()> { +pub struct MotorDriverDebug{ + endpoint: SendQ, + recv_q: RecvQ, + dispatch: dispatch::SendQ, +} + +/// Debug / example version of Motor Driver. +impl MotorDriverDebug { + pub fn new(send_q: dispatch::SendQ) -> Self { + let (s,r) = unbounded(); + MotorDriverDebug { + endpoint: s, + recv_q: r, + dispatch:send_q + } + } + + pub fn get_endpoint(&self) -> SendQ { + self.endpoint.clone() + } + + pub async fn run(&self) -> Result<()> { + //TODO: Add error propagation to all loops + loop { + match self.recv_q.recv().await { + Ok(cmd) => { + match self.handle_cmd(cmd).await { + Ok(_) => {} + Err(e) => { + error!("Unable to send commands to motor! {:?}", e); + panic!() + } + } + } + Err(e) => { + error!("Unable to receive commands for motor control! {:?}", e); + panic!(); + } + } + } + } + + async fn handle_cmd(&self, cmd: Commands) -> Result<()> { + match cmd { + Commands::StartUp => {self.start_up().await?;Ok(())} + Commands::StartDown => {self.start_down().await?;Ok(())} + Commands::Stop => {self.stop().await?;Ok(())} + } + } + + pub async fn start_up(&self) -> Result<()> { warn!("Starting motor, direction: Up"); + self.dispatch.send(Dispatch_Commands::NotifyMotorUp).await?; Ok(()) } - fn start_down(&mut self) -> Result<()> { + pub async fn start_down(&self) -> Result<()> { warn!("Starting motor, direction: Down"); + self.dispatch.send(Dispatch_Commands::NotifyMotorDown).await?; Ok(()) } - fn stop(&mut self) ->Result<()> { + pub async fn stop(&self) -> Result<()> { warn!("Stopping motor"); + self.dispatch.send(Dispatch_Commands::NotifyMotorStop).await?; Ok(()) } } - -//unsafe impl Send for MotorDriverDebug {} \ No newline at end of file