diff --git a/satrs-minisim/Cargo.toml b/satrs-minisim/Cargo.toml index 53910e1..72fbff9 100644 --- a/satrs-minisim/Cargo.toml +++ b/satrs-minisim/Cargo.toml @@ -18,3 +18,6 @@ path = "../../asynchronix/asynchronix" [dependencies.satrs] path = "../satrs" + +[dev-dependencies] +delegate = "0.12" diff --git a/satrs-minisim/src/acs.rs b/satrs-minisim/src/acs.rs index 604597d..45dc7b6 100644 --- a/satrs-minisim/src/acs.rs +++ b/satrs-minisim/src/acs.rs @@ -53,6 +53,8 @@ impl MagnetometerModel { } pub async fn send_sensor_values(&mut self, _: (), scheduler: &Scheduler) { + let current_time = scheduler.time(); + println!("current monotonic time: {:?}", current_time); let value = self.calculate_current_mgm_tuple(current_millis(scheduler.time())); let reply = SimReply { device: SimDevice::Mgm, diff --git a/satrs-minisim/src/controller.rs b/satrs-minisim/src/controller.rs index 0d604f9..3c1e91a 100644 --- a/satrs-minisim/src/controller.rs +++ b/satrs-minisim/src/controller.rs @@ -21,20 +21,38 @@ pub struct SimController { } impl SimController { - pub fn run(&mut self, t0: MonotonicTime) { - let mut t = t0 + Duration::from_millis(10); + pub fn run(&mut self, start_time: MonotonicTime) { + let mut t = start_time + Duration::from_millis(1); + self.sys_clock.synchronize(t); loop { self.simulation .step_until(t) .expect("simulation step failed"); - t += Duration::from_millis(10); - // TODO: Received and handle requests. + // Check for UDP requests every millisecond. + t += Duration::from_millis(1); + self.handle_sim_requests(); - // TODO: Incorporate network latency. self.sys_clock.synchronize(t); } } + pub fn handle_sim_requests(&mut self) { + loop { + match self.request_receiver.try_recv() { + Ok(request) => match request.device { + satrs_minisim::SimDevice::Mgm => self.handle_mgm_request(&request.request), + satrs_minisim::SimDevice::Mgt => self.handle_mgt_request(&request.request), + satrs_minisim::SimDevice::Pcdu => self.handle_pcdu_request(&request.request), + }, + Err(e) => match e { + mpsc::TryRecvError::Empty => break, + mpsc::TryRecvError::Disconnected => { + panic!("all request sender disconnected") + } + }, + } + } + } fn handle_mgm_request(&mut self, request: &str) { let mgm_request: serde_json::Result = serde_json::from_str(request); if mgm_request.is_err() { @@ -54,7 +72,7 @@ impl SimController { } fn handle_pcdu_request(&mut self, request: &str) { - let pcdu_request: serde_json::Result = serde_json::from_str(&request); + let pcdu_request: serde_json::Result = serde_json::from_str(request); if pcdu_request.is_err() { log::warn!( "received invalid PCDU request: {}", @@ -67,4 +85,6 @@ impl SimController { PcduRequest::RequestSwitchInfo => todo!(), } } + + fn handle_mgt_request(&mut self, request: &str) {} } diff --git a/satrs-minisim/src/lib.rs b/satrs-minisim/src/lib.rs index b9ed24c..8731a31 100644 --- a/satrs-minisim/src/lib.rs +++ b/satrs-minisim/src/lib.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum SimDevice { Mgm, Mgt, diff --git a/satrs-minisim/src/main.rs b/satrs-minisim/src/main.rs index bfb0c0b..4c5f1f6 100644 --- a/satrs-minisim/src/main.rs +++ b/satrs-minisim/src/main.rs @@ -1,5 +1,4 @@ use acs::MagnetometerModel; -use asynchronix::model::Model; use asynchronix::simulation::{Mailbox, SimInit}; use asynchronix::time::{MonotonicTime, SystemClock}; use controller::SimController; @@ -61,3 +60,106 @@ fn main() { 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 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(); + // Instantiate models and their mailboxes. + let mgm_sim = 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(); + + // Instantiate the simulator + let t0 = MonotonicTime::EPOCH; + let sys_clock = SystemClock::from_system_time(t0, SystemTime::now()); + let simulation = SimInit::with_num_threads(1) + .add_model(mgm_sim, mgm_mailbox) + .init(t0); + + Self { + sim_controller: SimController { + sys_clock, + request_receiver, + simulation, + mgm_addr, + pcdu_addr, + }, + 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 { + device: SimDevice::Mgm, + request: serde_json::to_string(&mgm_request).unwrap(), + }; + 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() {} +}