Initial rough-in of motor controller
This commit is contained in:
78
gem-remotes-esp32/src/dispatch.rs
Normal file
78
gem-remotes-esp32/src/dispatch.rs
Normal 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")}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user