use acs::MagnetometerModel; use asynchronix::simulation::{Mailbox, SimInit}; use asynchronix::time::{MonotonicTime, SystemClock}; use controller::SimController; use eps::PcduModel; use satrs_minisim::{SimReply, SimRequest}; use std::sync::mpsc; use std::thread; use std::time::{Duration, SystemTime}; use udp::{SharedSocketAddr, UdpTcServer, UdpTmClient}; mod acs; mod controller; mod eps; mod time; mod udp; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ThreadingModel { Default = 0, Single = 1, } fn create_sim_controller( threading_model: ThreadingModel, start_time: MonotonicTime, reply_sender: mpsc::Sender, request_receiver: mpsc::Receiver, ) -> SimController { // Instantiate models and their mailboxes. let mgm_model = MagnetometerModel::new(Duration::from_millis(50), reply_sender.clone()); let mgm_mailbox = Mailbox::new(); let mgm_addr = mgm_mailbox.address(); let pcdu_mailbox = Mailbox::new(); let pcdu_addr = pcdu_mailbox.address(); let mut pcdu_model = PcduModel::new(reply_sender.clone()); pcdu_model .mgm_switch .connect(MagnetometerModel::switch_device, &mgm_addr); // Instantiate the simulator let sys_clock = SystemClock::from_system_time(start_time, SystemTime::now()); let sim_init = if threading_model == ThreadingModel::Single { SimInit::with_num_threads(1) } else { SimInit::new() }; let simulation = sim_init .add_model(mgm_model, mgm_mailbox) .add_model(pcdu_model, pcdu_mailbox) .init(start_time); SimController::new(sys_clock, request_receiver, simulation, mgm_addr, pcdu_addr) } fn main() { let shared_socket_addr = SharedSocketAddr::default(); let (request_sender, request_receiver) = mpsc::channel(); let (reply_sender, reply_receiver) = mpsc::channel(); let t0 = MonotonicTime::EPOCH; let mut sim_ctrl = create_sim_controller(ThreadingModel::Default, t0, reply_sender, request_receiver); // This thread schedules the simulator. let sim_thread = thread::spawn(move || { sim_ctrl.run(t0); }); let mut server = UdpTcServer::new(request_sender, shared_socket_addr.clone()).unwrap(); // This thread manages the simulator UDP TC server. let udp_tc_thread = thread::spawn(move || { server.run(); }); let mut client = UdpTmClient::new(reply_receiver, 200, shared_socket_addr); // This thread manages the simulator UDP TM client. let udp_tm_thread = thread::spawn(move || { client.run(); }); sim_thread.join().expect("joining simulation thread failed"); udp_tc_thread.join().expect("joining UDP TC thread failed"); udp_tm_thread.join().expect("joining UDP TM thread failed"); } #[cfg(test)] mod tests { use delegate::delegate; use satrs_minisim::{ acs::{MgmRequest, MgmSensorValues}, SimDevice, SimReply, SimRequest, }; use crate::eps::PcduRequest; use super::*; struct SimTestbench { pub sim_controller: SimController, pub reply_receiver: mpsc::Receiver, pub request_sender: mpsc::Sender, } impl SimTestbench { fn new() -> Self { let (request_sender, request_receiver) = mpsc::channel(); let (reply_sender, reply_receiver) = mpsc::channel(); let t0 = MonotonicTime::EPOCH; let sim_ctrl = create_sim_controller(ThreadingModel::Single, t0, reply_sender, request_receiver); Self { sim_controller: sim_ctrl, reply_receiver, request_sender, } } delegate! { to self.sim_controller { pub fn handle_sim_requests(&mut self); } to self.sim_controller.simulation { pub fn step(&mut self); } } pub fn send_request(&self, request: SimRequest) -> Result<(), mpsc::SendError> { self.request_sender.send(request) } pub fn try_receive_next_reply(&self) -> Option { match self.reply_receiver.try_recv() { Ok(reply) => Some(reply), Err(e) => { if e == mpsc::TryRecvError::Empty { None } else { panic!("reply_receiver disconnected"); } } } } } #[test] fn test_basic_mgm_request() { let mut sim_testbench = SimTestbench::new(); let mgm_request = MgmRequest::RequestSensorData; let request = SimRequest::new(SimDevice::Mgm, mgm_request); sim_testbench .send_request(request) .expect("sending MGM request failed"); sim_testbench.handle_sim_requests(); sim_testbench.step(); let sim_reply = sim_testbench.try_receive_next_reply(); assert!(sim_reply.is_some()); let sim_reply = sim_reply.unwrap(); assert_eq!(sim_reply.device, SimDevice::Mgm); let reply: MgmSensorValues = serde_json::from_str(&sim_reply.reply) .expect("failed to deserialize MGM sensor values"); assert_eq!(reply.x, 0.0); assert_eq!(reply.y, 0.0); assert_eq!(reply.z, 0.0); } #[test] fn test_basic_mgm_request_switched_on() { let mut sim_testbench = SimTestbench::new(); let pcdu_request = PcduRequest::RequestSwitchInfo; let request = SimRequest::new(SimDevice::Pcdu, pcdu_request); } }