Created
          November 8, 2024 16:49 
        
      - 
      
 - 
        
Save dgehriger/f26e715605efa5d0e4fbb8cec5ef27dc to your computer and use it in GitHub Desktop.  
    Simple service architecture
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | use crossbeam_channel::{unbounded, Receiver, Sender}; | |
| use std::sync::{Arc, Mutex}; | |
| fn main() { | |
| // create a multi-producer, multi-consumer channel | |
| let (tx, rx) = unbounded(); | |
| let motion_controller = Arc::new(Mutex::new(RodBenderMotionControler::new())); | |
| // connect g_code_executor to motion_controller | |
| let gcode_executor = GCodeExecutor::new(motion_controller.clone(), rx.clone()); | |
| // connect jogging_executor to motion_controller | |
| let jogging_executor = JoggingExecutor::new(motion_controller.clone(), rx.clone()); | |
| let api_server = ApiServer::new(tx); | |
| // create a thread for G-code executor | |
| // Tokio: use tokio::spawn instead of std::thread::spawn | |
| std::thread::spawn(move || { | |
| gcode_executor.run(); | |
| }); | |
| // create a thread for jogging executor | |
| std::thread::spawn(move || { | |
| jogging_executor.run(); | |
| }); | |
| api_server.run() | |
| } | |
| pub enum ApiCommand { | |
| GCode(String), | |
| JogMoveTo(f64), | |
| Abort, | |
| } | |
| pub struct ApiServer { | |
| tx: Sender<ApiCommand>, | |
| } | |
| impl ApiServer { | |
| pub fn new(tx: Sender<ApiCommand>) -> ApiServer { | |
| ApiServer { tx } | |
| } | |
| // Tokio: make function async: pub async fn run(&self) | |
| pub fn run(&self) { | |
| loop { | |
| // read keyboard input and send it to the channel | |
| let mut input = String::new(); | |
| std::io::stdin().read_line(&mut input).unwrap(); | |
| if input.starts_with("G") { | |
| self.tx.send(ApiCommand::GCode(input)).unwrap(); | |
| } else if input.starts_with("J") { | |
| println!("Parsing input: {}", input); | |
| let x = input | |
| .trim() | |
| .split_whitespace() | |
| .last() | |
| .unwrap() | |
| .parse() | |
| .unwrap(); | |
| println!("Jogging to {}", x); | |
| self.tx.send(ApiCommand::JogMoveTo(x)).unwrap(); | |
| } else if input.starts_with("A") { | |
| self.tx.send(ApiCommand::Abort).unwrap(); | |
| } | |
| } | |
| } | |
| } | |
| pub struct GCodeExecutor { | |
| motion_controller: Arc<Mutex<dyn MotionController>>, | |
| rx: Receiver<ApiCommand>, | |
| } | |
| impl GCodeExecutor { | |
| pub fn new( | |
| motion_controller: Arc<Mutex<dyn MotionController>>, | |
| rx: Receiver<ApiCommand>, | |
| ) -> GCodeExecutor { | |
| GCodeExecutor { | |
| motion_controller, | |
| rx, | |
| } | |
| } | |
| // tokio: make function async: pub async fn run(&self) | |
| pub fn run(&self) { | |
| loop { | |
| // tokio: use self.rx.recv().await instead of self.rx.recv().unwrap() | |
| match self.rx.recv().unwrap() { | |
| ApiCommand::GCode(gcode) => { | |
| println!("Executing G-code: {}", gcode); | |
| } | |
| ApiCommand::Abort => { | |
| println!("Aborting G-code execution"); | |
| break; | |
| } | |
| _ => {} | |
| } | |
| } | |
| todo!() | |
| } | |
| } | |
| pub struct JoggingExecutor { | |
| motion_controller: Arc<Mutex<dyn MotionController>>, | |
| rx: Receiver<ApiCommand>, | |
| } | |
| impl JoggingExecutor { | |
| pub fn new( | |
| motion_controller: Arc<Mutex<dyn MotionController>>, | |
| rx: Receiver<ApiCommand>, | |
| ) -> JoggingExecutor { | |
| JoggingExecutor { | |
| motion_controller, | |
| rx, | |
| } | |
| } | |
| pub fn run(&self) { | |
| loop { | |
| match self.rx.recv().unwrap() { | |
| ApiCommand::JogMoveTo(x) => { | |
| println!("Jogging to {}", x); | |
| self.motion_controller.lock().unwrap().move_to(x); | |
| } | |
| ApiCommand::Abort => { | |
| println!("Aborting jogging"); | |
| break; | |
| } | |
| _ => { | |
| println!("Invalid command"); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| pub trait MotionController: Send { | |
| fn move_to(&self, x: f64); | |
| } | |
| pub struct RodBenderMotionControler {} | |
| impl RodBenderMotionControler { | |
| pub fn new() -> RodBenderMotionControler { | |
| RodBenderMotionControler {} | |
| } | |
| } | |
| impl MotionController for RodBenderMotionControler { | |
| fn move_to(&self, x: f64) { | |
| println!("Moving to {}", x); | |
| } | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment