Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit
176 lines
5.5 KiB
Rust
176 lines
5.5 KiB
Rust
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<SimReply>,
|
|
request_receiver: mpsc::Receiver<SimRequest>,
|
|
) -> 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<SimReply>,
|
|
pub request_sender: mpsc::Sender<SimRequest>,
|
|
}
|
|
|
|
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<SimRequest>> {
|
|
self.request_sender.send(request)
|
|
}
|
|
|
|
pub fn try_receive_next_reply(&self) -> Option<SimReply> {
|
|
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);
|
|
}
|
|
}
|