Initial rough-in of motor controller

This commit is contained in:
2024-08-17 15:10:06 -04:00
parent 3633f636c6
commit 3185746213
11 changed files with 653 additions and 62 deletions

View File

@ -0,0 +1,120 @@
use log::*; //{trace, debug, info, warn, error}
use anyhow::Result;
use esp_idf_svc::timer::{EspTaskTimerService, EspAsyncTimer};
use core::time::Duration;
use async_channel::{Receiver, Sender};
use futures_lite::FutureExt;
use crate::dispatch::Dispatch;
use crate::commands::Commands;
#[derive(Copy, Clone)]
enum State {
Running,
Stopped,
}
/// A timer that can be reset or canceled via message queue
/// Q is the type of enum on the receive Q, S on the send.
pub struct MessageTimer <Q, S> {
restart: Q,
cancel: Q,
done: S, // Send this when the timeout is hit
duration: Duration,
send_q: Sender<S>,
recv_q: Receiver<Q>,
state: State,
}
impl<Q: PartialEq, S: Copy> MessageTimer<Q, S> {
pub fn new(
restart: Q,
cancel: Q,
done: S,
duration:Duration,
send_q: Sender<S>,
recv_q: Receiver<Q>
) -> MessageTimer<Q, S> {
MessageTimer {
restart: restart,
cancel: cancel,
done: done,
duration: duration,
send_q: send_q,
recv_q: recv_q,
state: State::Stopped,
}
}
pub fn new_on_dispatch(
restart: Commands,
cancel: Commands,
done: Commands,
ms: u64,
dp: &mut Dispatch,
) -> MessageTimer<Commands, Commands> {
let cmds = vec![restart, cancel];
let s = dp.get_cmd_channel();
let r = dp.get_callback_channel(&cmds);
let duration = Duration::from_millis(ms);
MessageTimer {
restart:restart,
cancel: cancel,
done: done,
duration: duration,
send_q: s,
recv_q: r,
state: State::Stopped,
}
}
async fn wait_for_cmd(&self) -> Result<Q> {
Ok(self.recv_q.recv().await.unwrap())
}
async fn wait_with_timeout(&self, timer: &mut EspAsyncTimer) -> Result<Q> {
self.wait_for_cmd().or(async{
timer.after(self.duration).await?;
Err(anyhow::Error::from(std::io::Error::new(std::io::ErrorKind::TimedOut, "Timeout")))
}).await
}
async fn handle_cmd(&mut self, cmd: Result<Q>) {
match cmd {
Ok(msg) => {
if msg == self.restart {
self.state = State::Running; // timer will automatically reset
}
else if msg == self.cancel {
self.state = State::Stopped;
}
else {
warn!("Spurious messages have reset a timer!");
}
}
Err(_) => {
trace!("Timeout reached");
self.send_q.send(self.done).await.expect("Failed to send timeout");
}
}
}
pub async fn run(&mut self) -> Result<()> {
let mut cmd;
let timer_service = EspTaskTimerService::new()?;
let mut async_timer = timer_service.timer_async()?;
loop {
match self.state {
State::Running => {
cmd = self.wait_with_timeout(&mut async_timer).await;
}
State::Stopped => {
cmd = self.wait_for_cmd().await;
}
}
self.handle_cmd(cmd).await;
}
}
}