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,78 @@
use std::mem::discriminant;
use std::collections::HashMap;
use std::vec::Vec;
use async_channel::{unbounded, Receiver, Sender};
use strum::EnumCount;
use crate::commands::{Commands, CmdType};
use log::*; //{trace, debug, info, warn, error}
pub type SendQ = Sender<Commands>;
pub type RecvQ = Receiver<Commands>;
//TODO: Making this generic over a <C> for commands would make it a useful small event handler.
pub struct Dispatch {
callbacks: HashMap<CmdType, Vec<SendQ> >,
recv: RecvQ, // Channel to listen to incomming commands
endpoint: SendQ, // Endpoint to clone to hand to other modules, so that they can send commands
}
impl Dispatch {
pub fn new() -> Dispatch {
let (s, r) = unbounded();
let mut hmap = HashMap::new();
hmap.reserve(Commands::COUNT);
Dispatch { callbacks: hmap, recv: r, endpoint: s}
}
/// Get a channel receiver that will get callbacks for all commands in the listen_for vec.
pub fn get_callback_channel(&mut self, listen_for: &Vec<Commands>) -> RecvQ {
let (send, rec) = unbounded();
for cmd in listen_for {
let callback_list = self.callbacks.get_mut(&discriminant(&cmd));
match callback_list {
Some(callback) => {
callback.push(send.clone());
trace!("Adding {:?} to callbacks", cmd);
}
None => {
let mut callback = Vec::new();
callback.push(send.clone());
self.callbacks.insert(discriminant(&cmd), callback);
trace!("Created {:?} callback", cmd);
}
}
}
rec
}
//TODO: Make a discriminant version of this function that takes a vec of discriminants
//TODO: Most of these channels could be fixed size instead unbound; probably only the incomming channel needs to be large.
/// Get a channel sender that will send commands to this dispatcher
pub fn get_cmd_channel(&mut self) -> SendQ {
self.endpoint.clone()
}
/// Wait on incomming commands and dispatch them
pub async fn cmd_loop(&self) -> anyhow::Result<()> {
loop {
debug!("Dispatch waiting on commands");
let cmd = self.recv.recv().await?;
debug!("Dispatch got command {:?}", cmd);
let cmd_type = discriminant(&cmd);
let found_listeners = self.callbacks.get(&cmd_type);
match found_listeners {
Some(listeners) => {
for listener in listeners {
trace!("Sending cmd {:?}", cmd);
listener.send(cmd.clone()).await?;
}
}
None => {debug!("Dispatch found no listeners for a command")}
}
}
}
}