ftswarm_emulator/
lib.rs

1use std::collections::VecDeque;
2use log::{info, trace};
3use ftswarm_proto::command::direct::FtSwarmDirectCommand;
4use ftswarm_proto::command::FtSwarmCommand;
5use ftswarm_proto::command::rpc::{FtSwarmRPCCommand, RpcFunction};
6use ftswarm_proto::Deserialized;
7use ftswarm_serial::{SerialError, SwarmSerialPort};
8
9pub struct EmulatedSerialPort(VecDeque<String>);
10
11impl Default for EmulatedSerialPort {
12    fn default() -> Self {
13        Self::new()
14    }
15}
16
17impl EmulatedSerialPort {
18    pub fn new() -> EmulatedSerialPort {
19        EmulatedSerialPort(VecDeque::new())
20    }
21
22    fn handle_direct_command(&mut self, command: FtSwarmDirectCommand) {
23        match command {
24            FtSwarmDirectCommand::Help => { self.0.push_back("Help".to_string()); }
25            FtSwarmDirectCommand::Setup => { self.0.push_back("Setup".to_string()); }
26            FtSwarmDirectCommand::Halt => {}
27            FtSwarmDirectCommand::Whoami => {self.0.push_back("ftSwarm100/kelda".to_string()); }
28            FtSwarmDirectCommand::Uptime => { self.0.push_back("uptime: 31.000 s".to_string()); }
29            FtSwarmDirectCommand::StartCli => {}
30        }
31    }
32
33    fn handle_rpc_command(&mut self, command: FtSwarmRPCCommand) {
34        let functions_to_ok = [RpcFunction::Show,
35            RpcFunction::TriggerUserEvent,
36            RpcFunction::SetMicroStepMode,
37            RpcFunction::SetSensorType,
38            RpcFunction::OnTrigger,
39            RpcFunction::SetActorType,
40            RpcFunction::SetSpeed,
41            RpcFunction::SetMotionType,
42            RpcFunction::SetPosition,
43            RpcFunction::SetOffset,
44            RpcFunction::SetColor,
45            RpcFunction::SetBrightness,
46            RpcFunction::SetRegister];
47
48        std::thread::sleep(std::time::Duration::from_millis(10));
49        match command.function {
50            RpcFunction::Subscribe => {}
51            _ => {
52                if functions_to_ok.contains(&command.function) {
53                    self.0.push_back("R: Ok".to_string());
54                    trace!("Emulator responded with Ok");
55                } else {
56                    self.0.push_back("R: 0".to_string());
57                    trace!("Emulator responded with 0");
58                }
59            }
60        }
61    }
62}
63
64impl SwarmSerialPort for EmulatedSerialPort {
65    fn available(&self) -> Result<bool, SerialError> {
66        Ok(!self.0.is_empty())
67    }
68
69    fn read_line(&mut self) -> Result<String, SerialError> {
70        self.0.pop_front().ok_or(SerialError::Timeout)
71    }
72
73    fn write_line(&mut self, line: String) -> Result<(), SerialError> {
74        let command = FtSwarmCommand::deserialize(&line).map_err(|_| SerialError::EncodingError)?;
75        match command {
76            FtSwarmCommand::RPC(command) => {
77                info!("Emulator received RPC command: {:?}", command);
78                self.handle_rpc_command(command);
79            }
80            FtSwarmCommand::Direct(command) => {
81                info!("Emulator received direct command: {:?}", command);
82                self.handle_direct_command(command);
83            }
84        }
85        Ok(())
86    }
87
88    fn block_until(&mut self, _: String) -> Result<(), SerialError> {
89        info!("Emulator has started");
90        Ok(())
91    }
92}
93
94#[cfg(test)]
95mod tests;