Made motor driver independent task

This commit is contained in:
2024-08-24 00:35:12 -04:00
parent cc72a23176
commit 3cf3dc5936
4 changed files with 90 additions and 39 deletions

View File

@ -23,6 +23,10 @@ pub enum Commands {
ButtonTimerExpired, ButtonTimerExpired,
ButtonTimerRestart, ButtonTimerRestart,
ButtonTimerClear, ButtonTimerClear,
NotifyMotorUp,
NotifyMotorDown,
NotifyMotorStop,
} }
pub type CmdType = std::mem::Discriminant<Commands>; pub type CmdType = std::mem::Discriminant<Commands>;

View File

@ -10,7 +10,6 @@ use log::*; //{trace, debug, info, warn, error}
use anyhow::Result; use anyhow::Result;
use async_executor::Executor; use async_executor::Executor;
use futures_lite::future; use futures_lite::future;
use std::boxed::Box;
// Debug modules // Debug modules
mod test_console; mod test_console;
@ -38,35 +37,23 @@ fn main() {
//log::set_max_level(log::LevelFilter::Info); //log::set_max_level(log::LevelFilter::Info);
match future::block_on(main_loop()) { match future::block_on(main_loop()) {
Ok(_) => {error!("Exited main loop normally, but this should be impossible.")} Ok(_) => {error!("Exited main loop with no errors, but this should not happen."); panic!();}
Err(e) => {error!("Exited main loop with error {}", e)} 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<()> { async fn main_loop() -> Result<()> {
info!("Entering main loop"); info!("Entering main loop");
// Create dispatch early so it can outlive most other things // Create dispatch early so it can outlive most other things
let mut dp = dispatch::Dispatch::new(); let mut dp = dispatch::Dispatch::new();
// Debug Drivers // Debug Drivers (TODO: remove debug)
let motor_driver = Box::new(motor_driver::MotorDriverDebug {}); let motor_driver = motor_driver::MotorDriverDebug::new(dp.get_cmd_channel());
// Setup of various drivers that need to out-live the executor // Setup of various drivers that need to out-live the executor
let m_chan = motor_controller::Controller::prepare_controller(&mut dp); 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 // Setup callback timers
let mut button_timer = MessageTimer::<Commands, Commands>::new_on_dispatch( let mut button_timer = MessageTimer::<Commands, Commands>::new_on_dispatch(
Commands::ButtonTimerRestart, Commands::ButtonTimerRestart,
@ -85,7 +72,7 @@ async fn main_loop() -> Result<()> {
let executor = Executor::new(); let executor = Executor::new();
let mut tasks:Vec<_> = Vec::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(); let cli_endpoint = dp.get_cmd_channel();
tasks.push(executor.spawn(test_console::start_cli(cli_endpoint))); tasks.push(executor.spawn(test_console::start_cli(cli_endpoint)));
//tasks.push(executor.spawn(test_loop())); //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(button_timer.run()));
tasks.push(executor.spawn(stopping_timer.run())); tasks.push(executor.spawn(stopping_timer.run()));
tasks.push(executor.spawn(ble_server.run())); tasks.push(executor.spawn(ble_server.run()));
tasks.push(executor.spawn(motor_driver.run()));
tasks.push(executor.spawn(dp.cmd_loop())); tasks.push(executor.spawn(dp.cmd_loop()));
//Once we have all our tasks, await on them all to run them in parallel. //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"); info!("exiting main loop");
Ok(()) Ok(())
} }
//TODO: check many of these mut functions to see if they don't need to be.

View File

@ -4,10 +4,10 @@
use log::*; //{trace, debug, info, warn, error} use log::*; //{trace, debug, info, warn, error}
//use async_channel::Receiver; //use async_channel::Receiver;
use anyhow::Result; use anyhow::Result;
use std::boxed::Box;
use crate::commands::Commands; 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}; use crate::dispatch::{Dispatch, RecvQ, SendQ};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
@ -23,16 +23,16 @@ pub struct Controller {
state: ControllerStates, state: ControllerStates,
recv: RecvQ, recv: RecvQ,
send: SendQ, send: SendQ,
driver: Box<dyn MotorDriver>, motor_q: MotorSendQ
} }
impl Controller { impl Controller {
pub fn new(recv: RecvQ, send: SendQ, driver: Box<dyn MotorDriver>) -> Controller { pub fn new(recv: RecvQ, send: SendQ, motor_q: MotorSendQ) -> Controller {
Controller { Controller {
state: ControllerStates::Stopping, state: ControllerStates::Stopping,
recv: recv, recv: recv,
send: send, send: send,
driver: driver} motor_q: motor_q}
} }
/// Tell the message dispatch which messages we are interested in receiving, and get /// Tell the message dispatch which messages we are interested in receiving, and get
@ -56,15 +56,15 @@ impl Controller {
ControllerStates::Stopped => {} ControllerStates::Stopped => {}
ControllerStates::Stopping => { ControllerStates::Stopping => {
self.send.send(Commands::StopTimerRestart).await?; self.send.send(Commands::StopTimerRestart).await?;
self.driver.stop()?; self.motor_q.send(MotorCommands::Stop).await?;
} }
ControllerStates::GoingUp => { ControllerStates::GoingUp => {
self.send.send(Commands::ButtonTimerRestart).await?; self.send.send(Commands::ButtonTimerRestart).await?;
self.driver.start_up()?; self.motor_q.send(MotorCommands::StartUp).await?;
} }
ControllerStates::GoingDown => { ControllerStates::GoingDown => {
self.send.send(Commands::ButtonTimerRestart).await?; self.send.send(Commands::ButtonTimerRestart).await?;
self.driver.start_down()?; self.motor_q.send(MotorCommands::StartDown).await?;
} }
} }
Ok(()) Ok(())

View File

@ -2,28 +2,85 @@
use log::*; //{trace, debug, info, warn, error} use log::*; //{trace, debug, info, warn, error}
use anyhow::Result; use anyhow::Result;
use async_channel::{unbounded, Receiver, Sender};
use std::panic;
pub trait MotorDriver: Send + Sync { use crate::dispatch;
fn start_up(&mut self) -> Result<()>; use crate::commands::Commands as Dispatch_Commands;
fn start_down(&mut self) -> Result<()>;
fn stop(&mut self) -> Result<()>; #[derive(Clone, Copy, Debug)]
pub enum Commands {
StartUp,
StartDown,
Stop
} }
pub struct MotorDriverDebug {} pub type SendQ = Sender<Commands>;
pub type RecvQ = Receiver<Commands>;
impl MotorDriver for MotorDriverDebug { pub struct MotorDriverDebug{
fn start_up(&mut self) -> Result<()> { 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"); warn!("Starting motor, direction: Up");
self.dispatch.send(Dispatch_Commands::NotifyMotorUp).await?;
Ok(()) Ok(())
} }
fn start_down(&mut self) -> Result<()> { pub async fn start_down(&self) -> Result<()> {
warn!("Starting motor, direction: Down"); warn!("Starting motor, direction: Down");
self.dispatch.send(Dispatch_Commands::NotifyMotorDown).await?;
Ok(()) Ok(())
} }
fn stop(&mut self) ->Result<()> { pub async fn stop(&self) -> Result<()> {
warn!("Stopping motor"); warn!("Stopping motor");
self.dispatch.send(Dispatch_Commands::NotifyMotorStop).await?;
Ok(()) Ok(())
} }
} }
//unsafe impl Send for MotorDriverDebug {}