const BUTTON_HOLD_TIME_MS: u64 = 500; const STOP_SAFETY_TIME_MS: u64 = 2000; // Crates used in release use log::*; //{trace, debug, info, warn, error} use anyhow::Result; use async_executor::Executor; use futures_lite::future; use std::panic; use std::ops::Deref; // Debug modules mod test_console; // Release modules mod commands; mod dispatch; mod motor_controller; mod motor_driver; mod message_timer; mod ble_server; use crate::message_timer::MessageTimer; use crate::commands::Commands; //TODO: limit switch driver, would be good in long run if it checked limit switches periodically (every 1s?) to ensure they are still functioning fn main() { // Do basic initialization esp_idf_svc::sys::link_patches(); esp_idf_svc::log::EspLogger::initialize_default(); // Set log level based on compiler flags #[cfg(debug_assertions)] log::set_max_level(log::LevelFilter::Trace); #[cfg(not(debug_assertions))] log::set_max_level(log::LevelFilter::Info); // Set panic to use error! instead of write! (as we will potentially log errors) panic::set_hook(Box::new(|panic_info| { let (filename, line) = panic_info.location().map(|loc| (loc.file(), loc.line())) .unwrap_or(("", 0)); let cause = panic_info.payload().downcast_ref::().map(String::deref); let cause = cause.unwrap_or_else(|| panic_info.payload().downcast_ref::<&str>().map(|s| *s) .unwrap_or("") ); error!("A panic occurred at {}:{}: {}", filename, line, cause); })); // Start up our main loop match future::block_on(main_loop()) { Ok(_) => {error!("Exited main loop with no errors, but this should not happen."); panic!();} Err(e) => {error!("Exited main loop with error {}", e); panic!();} }; } 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 (TODO DEBUG: remove debug) let motor_driver = motor_driver::MotorDriverDebug::new(); // 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.get_endpoint()); // Setup callback timers let mut button_timer = MessageTimer::::new_on_dispatch( Commands::ButtonTimerRestart, Commands::ButtonTimerClear, Commands::ButtonTimerExpired, BUTTON_HOLD_TIME_MS, &mut dp); let mut stopping_timer = MessageTimer::::new_on_dispatch( Commands::StopTimerRestart, Commands::StopTimerClear, Commands::StopTimerExpired, STOP_SAFETY_TIME_MS, &mut dp); let ble_server = ble_server::BleServer::new(&mut dp); let executor = Executor::new(); let mut tasks:Vec<_> = Vec::new(); //Queue Up debug tasks (TODO DEBUG: remove debug) let cli_endpoint = dp.get_cmd_channel(); tasks.push(executor.spawn(test_console::start_cli(cli_endpoint))); // Queueu up our async tasks tasks.push(executor.spawn(motor_control.run())); 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. for task in tasks { executor.run(task).await?; } info!("exiting main loop"); Ok(()) }