More consistent error handling in loops
This commit is contained in:
@ -8,7 +8,7 @@ use closure::closure;
|
|||||||
use crate::dispatch::{Dispatch, RecvQ, SendQ};
|
use crate::dispatch::{Dispatch, RecvQ, SendQ};
|
||||||
use crate::commands::Commands;
|
use crate::commands::Commands;
|
||||||
|
|
||||||
// TODO: test these values to see if they are suitable
|
// TODO HARDWARE: test these values to see if they are suitable
|
||||||
const BLE_MIN_INTERVAL: u16 = 24; // x 1.25ms
|
const BLE_MIN_INTERVAL: u16 = 24; // x 1.25ms
|
||||||
const BLE_MAX_INTERVAL: u16 = 48; // x 1.25ms
|
const BLE_MAX_INTERVAL: u16 = 48; // x 1.25ms
|
||||||
const BLE_LATENCY: u16 = 0; // Number of packets that can be missed, extending interval
|
const BLE_LATENCY: u16 = 0; // Number of packets that can be missed, extending interval
|
||||||
@ -106,10 +106,10 @@ impl BleServer {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
debug!("Waiting for updates that should be notified via bluetooth");
|
debug!("Waiting for updates that should be notified via bluetooth");
|
||||||
let cmd = self.recv_q.recv().await?;
|
let cmd =self.recv_q.recv().await.expect("Bluetooth notification queue unexpectedly closed");
|
||||||
trace!("Received update to bluetooth variable {:?}", cmd);
|
trace!("Received update to bluetooth variable {:?}", cmd);
|
||||||
match cmd {
|
match cmd {
|
||||||
// TODO: This logic (if one button is pressed others are released) could be done in app instead.
|
// TODO DISCUSS: This logic (if one button is pressed others are released) could be done in app instead.
|
||||||
Commands::NotifyMotorUp => {
|
Commands::NotifyMotorUp => {
|
||||||
button_up.lock().set_value(&BUTTON_PRESSED).notify();
|
button_up.lock().set_value(&BUTTON_PRESSED).notify();
|
||||||
button_down.lock().set_value(&BUTTON_RELEASED).notify();
|
button_down.lock().set_value(&BUTTON_RELEASED).notify();
|
||||||
|
|||||||
@ -57,7 +57,7 @@ impl Dispatch {
|
|||||||
pub async fn cmd_loop(&self) -> anyhow::Result<()> {
|
pub async fn cmd_loop(&self) -> anyhow::Result<()> {
|
||||||
loop {
|
loop {
|
||||||
debug!("Dispatch waiting on commands");
|
debug!("Dispatch waiting on commands");
|
||||||
let cmd = self.recv.recv().await?;
|
let cmd = self.recv.recv().await.expect("Incoming event queue failed unexpectedly");
|
||||||
debug!("Dispatch got command {:?}", cmd);
|
debug!("Dispatch got command {:?}", cmd);
|
||||||
let cmd_type = discriminant(&cmd);
|
let cmd_type = discriminant(&cmd);
|
||||||
let found_listeners = self.callbacks.get(&cmd_type);
|
let found_listeners = self.callbacks.get(&cmd_type);
|
||||||
@ -65,7 +65,7 @@ impl Dispatch {
|
|||||||
Some(listeners) => {
|
Some(listeners) => {
|
||||||
for listener in listeners {
|
for listener in listeners {
|
||||||
trace!("Sending cmd {:?}", cmd);
|
trace!("Sending cmd {:?}", cmd);
|
||||||
listener.send(cmd.clone()).await?;
|
listener.send(cmd.clone()).await.expect("Outgoing event queue failed unexpectedly");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {debug!("Dispatch found no listeners for a command")}
|
None => {debug!("Dispatch found no listeners for a command")}
|
||||||
|
|||||||
@ -31,6 +31,7 @@ fn main() {
|
|||||||
esp_idf_svc::sys::link_patches();
|
esp_idf_svc::sys::link_patches();
|
||||||
esp_idf_svc::log::EspLogger::initialize_default();
|
esp_idf_svc::log::EspLogger::initialize_default();
|
||||||
log::set_max_level(log::LevelFilter::Trace);
|
log::set_max_level(log::LevelFilter::Trace);
|
||||||
|
//TODO DEBUG: remove trace logging
|
||||||
//log::set_max_level(log::LevelFilter::Info);
|
//log::set_max_level(log::LevelFilter::Info);
|
||||||
|
|
||||||
// Set panic to use error! instead of write! (as we will potentially log errors)
|
// Set panic to use error! instead of write! (as we will potentially log errors)
|
||||||
@ -61,7 +62,7 @@ async fn main_loop() -> Result<()> {
|
|||||||
// 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 (TODO: remove debug)
|
// Debug Drivers (TODO DEBUG: remove debug)
|
||||||
let motor_driver = motor_driver::MotorDriverDebug::new(dp.get_cmd_channel());
|
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
|
||||||
@ -85,12 +86,9 @@ 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 debug)
|
//Queue Up debug tasks (TODO DEBUG: 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()));
|
|
||||||
//let t_chan = test_driver_tattle::prepare_tattle(&mut dp).expect("Failed to set up debugging copycat driver");
|
|
||||||
//tasks.push(executor.spawn(test_driver_tattle::start_tattle(t_chan)));
|
|
||||||
|
|
||||||
// Queueu up our async tasks
|
// Queueu up our async tasks
|
||||||
tasks.push(executor.spawn(motor_control.run()));
|
tasks.push(executor.spawn(motor_control.run()));
|
||||||
|
|||||||
@ -70,7 +70,7 @@ impl<Q: PartialEq, S: Copy> MessageTimer<Q, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_cmd(&self) -> Result<Q> {
|
async fn wait_for_cmd(&self) -> Result<Q> {
|
||||||
Ok(self.recv_q.recv().await.unwrap())
|
Ok(self.recv_q.recv().await.expect("Timer command queue unexpectedly failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_with_timeout(&self, timer: &mut EspAsyncTimer) -> Result<Q> {
|
async fn wait_with_timeout(&self, timer: &mut EspAsyncTimer) -> Result<Q> {
|
||||||
@ -101,18 +101,17 @@ impl<Q: PartialEq, S: Copy> MessageTimer<Q, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&mut self) -> Result<()> {
|
pub async fn run(&mut self) -> Result<()> {
|
||||||
let mut cmd;
|
|
||||||
let timer_service = EspTaskTimerService::new()?;
|
let timer_service = EspTaskTimerService::new()?;
|
||||||
let mut async_timer = timer_service.timer_async()?;
|
let mut async_timer = timer_service.timer_async()?;
|
||||||
loop {
|
loop {
|
||||||
match self.state {
|
let cmd = match self.state {
|
||||||
State::Running => {
|
State::Running => {
|
||||||
cmd = self.wait_with_timeout(&mut async_timer).await;
|
self.wait_with_timeout(&mut async_timer).await
|
||||||
}
|
}
|
||||||
State::Stopped => {
|
State::Stopped => {
|
||||||
cmd = self.wait_for_cmd().await;
|
self.wait_for_cmd().await
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
self.handle_cmd(cmd).await;
|
self.handle_cmd(cmd).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,6 +54,7 @@ impl Controller {
|
|||||||
async fn enter_state(&mut self, new_s: &ControllerStates) -> Result<()> {
|
async fn enter_state(&mut self, new_s: &ControllerStates) -> Result<()> {
|
||||||
match new_s {
|
match new_s {
|
||||||
ControllerStates::Stopped => {
|
ControllerStates::Stopped => {
|
||||||
|
// Other notify commands are sent directly from the motor controller
|
||||||
self.send.send(Commands::NotifyMotorStopped).await?;
|
self.send.send(Commands::NotifyMotorStopped).await?;
|
||||||
}
|
}
|
||||||
ControllerStates::Stopping => {
|
ControllerStates::Stopping => {
|
||||||
@ -85,7 +86,6 @@ impl Controller {
|
|||||||
|
|
||||||
async fn exit_state(&mut self, old_s: &ControllerStates) -> Result <()> {
|
async fn exit_state(&mut self, old_s: &ControllerStates) -> Result <()> {
|
||||||
match old_s {
|
match old_s {
|
||||||
//TODO: We need to notify the BLE controller!
|
|
||||||
ControllerStates::Stopped => {}
|
ControllerStates::Stopped => {}
|
||||||
ControllerStates::Stopping => {
|
ControllerStates::Stopping => {
|
||||||
self.send.send(Commands::StopTimerClear).await?;
|
self.send.send(Commands::StopTimerClear).await?;
|
||||||
@ -184,11 +184,11 @@ impl Controller {
|
|||||||
self.state = ControllerStates::Stopping;
|
self.state = ControllerStates::Stopping;
|
||||||
self.enter_state(&ControllerStates::Stopping).await?;
|
self.enter_state(&ControllerStates::Stopping).await?;
|
||||||
loop {
|
loop {
|
||||||
let cmd = self.recv.recv().await?;
|
let cmd = self.recv.recv().await.expect("Motor controller command queue unexpectedly failed");
|
||||||
trace!("Got command {:?}",cmd);
|
trace!("Got command {:?}",cmd);
|
||||||
let new_s = self.handle_cmd(&cmd);
|
let new_s = self.handle_cmd(&cmd);
|
||||||
trace!("State current {:?} new {:?}", self.state, new_s);
|
trace!("State current {:?} new {:?}", self.state, new_s);
|
||||||
self.transition_state(&self.state.clone(), &new_s).await?
|
self.transition_state(&self.state.clone(), &new_s).await.expect("Unexpected state change failure in motor controller");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
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 async_channel::{unbounded, Receiver, Sender};
|
||||||
use std::panic;
|
|
||||||
|
|
||||||
use crate::dispatch;
|
use crate::dispatch;
|
||||||
use crate::commands::Commands as Dispatch_Commands;
|
use crate::commands::Commands as Dispatch_Commands;
|
||||||
@ -40,32 +39,19 @@ impl MotorDriverDebug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&self) -> Result<()> {
|
pub async fn run(&self) -> Result<()> {
|
||||||
//TODO: Add error propagation to all loops
|
|
||||||
loop {
|
loop {
|
||||||
match self.recv_q.recv().await {
|
let cmd = self.recv_q.recv().await.expect("Unexpected failure in motor driver command queue");
|
||||||
Ok(cmd) => {
|
self.handle_cmd(cmd).await.expect("Unexpected failure of motor driver notification queue");
|
||||||
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<()> {
|
async fn handle_cmd(&self, cmd: Commands) -> Result<()> {
|
||||||
match cmd {
|
match cmd {
|
||||||
Commands::StartUp => {self.start_up().await?;Ok(())}
|
Commands::StartUp => {self.start_up().await?;}
|
||||||
Commands::StartDown => {self.start_down().await?;Ok(())}
|
Commands::StartDown => {self.start_down().await?;}
|
||||||
Commands::Stop => {self.stop().await?;Ok(())}
|
Commands::Stop => {self.stop().await?;}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_up(&self) -> Result<()> {
|
pub async fn start_up(&self) -> Result<()> {
|
||||||
|
|||||||
@ -217,7 +217,7 @@ pub async fn start_cli(dispatch: Sender<Commands>) -> anyhow::Result<()> {
|
|||||||
let mut buf = [0_u8; 1];
|
let mut buf = [0_u8; 1];
|
||||||
let mut async_timer = timer_service.timer_async()?;
|
let mut async_timer = timer_service.timer_async()?;
|
||||||
loop {
|
loop {
|
||||||
async_timer.after(Duration::from_millis(SLEEP_TIME_MS)).await?;
|
async_timer.after(Duration::from_millis(SLEEP_TIME_MS)).await?; // no need to panic on test console driver timer failure
|
||||||
match reader.read_exact(&mut buf) {
|
match reader.read_exact(&mut buf) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
//cli.process_byte::<Menu, _>(buf[0], &mut Menu::processor(process_menu))?;
|
//cli.process_byte::<Menu, _>(buf[0], &mut Menu::processor(process_menu))?;
|
||||||
|
|||||||
Reference in New Issue
Block a user