unittests are working well
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit

This commit is contained in:
Robin Müller 2024-03-07 17:11:24 +01:00
parent c9f71125a3
commit 3dd6ad6155
Signed by: muellerr
GPG Key ID: A649FB78196E3849
6 changed files with 168 additions and 62 deletions

View File

@ -4,7 +4,7 @@ use asynchronix::{
model::{Model, Output}, model::{Model, Output},
time::Scheduler, time::Scheduler,
}; };
use satrs::power::SwitchState; use satrs::power::{SwitchState, SwitchStateBinary};
use satrs_minisim::{ use satrs_minisim::{
acs::{MgmSensorValues, MgtDipole, MGT_GEN_MAGNETIC_FIELD}, acs::{MgmSensorValues, MgtDipole, MGT_GEN_MAGNETIC_FIELD},
SimDevice, SimReply, SimDevice, SimReply,
@ -32,7 +32,7 @@ const PHASE_Z: f32 = 0.2;
/// a general purpose OS, but self self-sampling at a relatively high rate (20-40 ms) might /// a general purpose OS, but self self-sampling at a relatively high rate (20-40 ms) might
/// stil lbe possible. /// stil lbe possible.
pub struct MagnetometerModel { pub struct MagnetometerModel {
pub switch_state: SwitchState, pub switch_state: SwitchStateBinary,
pub periodicity: Duration, pub periodicity: Duration,
pub external_mag_field: Option<MgmSensorValues>, pub external_mag_field: Option<MgmSensorValues>,
pub reply_sender: mpsc::Sender<SimReply>, pub reply_sender: mpsc::Sender<SimReply>,
@ -41,14 +41,14 @@ pub struct MagnetometerModel {
impl MagnetometerModel { impl MagnetometerModel {
pub fn new(periodicity: Duration, reply_sender: mpsc::Sender<SimReply>) -> Self { pub fn new(periodicity: Duration, reply_sender: mpsc::Sender<SimReply>) -> Self {
Self { Self {
switch_state: SwitchState::Off, switch_state: SwitchStateBinary::Off,
periodicity, periodicity,
external_mag_field: None, external_mag_field: None,
reply_sender, reply_sender,
} }
} }
pub async fn switch_device(&mut self, switch_state: SwitchState) { pub async fn switch_device(&mut self, switch_state: SwitchStateBinary) {
self.switch_state = switch_state; self.switch_state = switch_state;
} }
@ -72,7 +72,7 @@ impl MagnetometerModel {
} }
fn calculate_current_mgm_tuple(&mut self, time_ms: u64) -> MgmSensorValues { fn calculate_current_mgm_tuple(&mut self, time_ms: u64) -> MgmSensorValues {
if let SwitchState::On = self.switch_state { if SwitchStateBinary::On == self.switch_state {
if let Some(ext_field) = self.external_mag_field { if let Some(ext_field) = self.external_mag_field {
return ext_field; return ext_field;
} }

View File

@ -1,7 +1,10 @@
use std::{sync::mpsc, time::Duration}; use std::{
sync::mpsc,
time::{Duration, SystemTime},
};
use asynchronix::{ use asynchronix::{
simulation::{Address, Simulation}, simulation::{Address, Mailbox, SimInit, Simulation},
time::{Clock, MonotonicTime, SystemClock}, time::{Clock, MonotonicTime, SystemClock},
}; };
use satrs_minisim::{acs::MgmRequest, SimRequest}; use satrs_minisim::{acs::MgmRequest, SimRequest};
@ -21,6 +24,22 @@ pub struct SimController {
} }
impl SimController { impl SimController {
pub fn new(
sys_clock: SystemClock,
request_receiver: mpsc::Receiver<SimRequest>,
simulation: Simulation,
mgm_addr: Address<MagnetometerModel>,
pcdu_addr: Address<PcduModel>,
) -> Self {
Self {
sys_clock,
request_receiver,
simulation,
mgm_addr,
pcdu_addr,
}
}
pub fn run(&mut self, start_time: MonotonicTime) { pub fn run(&mut self, start_time: MonotonicTime) {
let mut t = start_time + Duration::from_millis(1); let mut t = start_time + Duration::from_millis(1);
self.sys_clock.synchronize(t); self.sys_clock.synchronize(t);
@ -39,10 +58,10 @@ impl SimController {
pub fn handle_sim_requests(&mut self) { pub fn handle_sim_requests(&mut self) {
loop { loop {
match self.request_receiver.try_recv() { match self.request_receiver.try_recv() {
Ok(request) => match request.device { Ok(request) => match request.device() {
satrs_minisim::SimDevice::Mgm => self.handle_mgm_request(&request.request), satrs_minisim::SimDevice::Mgm => self.handle_mgm_request(request.request()),
satrs_minisim::SimDevice::Mgt => self.handle_mgt_request(&request.request), satrs_minisim::SimDevice::Mgt => self.handle_mgt_request(request.request()),
satrs_minisim::SimDevice::Pcdu => self.handle_pcdu_request(&request.request), satrs_minisim::SimDevice::Pcdu => self.handle_pcdu_request(request.request()),
}, },
Err(e) => match e { Err(e) => match e {
mpsc::TryRecvError::Empty => break, mpsc::TryRecvError::Empty => break,
@ -83,6 +102,7 @@ impl SimController {
let pcdu_request = pcdu_request.unwrap(); let pcdu_request = pcdu_request.unwrap();
match pcdu_request { match pcdu_request {
PcduRequest::RequestSwitchInfo => todo!(), PcduRequest::RequestSwitchInfo => todo!(),
PcduRequest::SwitchDevice => todo!(),
} }
} }

View File

@ -1,10 +1,19 @@
use asynchronix::model::{Model, Output}; use std::{sync::mpsc, time::Duration};
use satrs::power::{SwitchState, SwitchStateBinary};
use asynchronix::{
model::{Model, Output},
time::Scheduler,
};
use satrs::power::SwitchStateBinary;
use satrs_minisim::{SimDevice, SimReply};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize)] pub const SWITCH_INFO_DELAY_MS: u64 = 10;
pub struct PcduTuple {}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct SwitchInfo(Vec<SwitchStateBinary>);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PcduSwitches { pub enum PcduSwitches {
Mgm = 0, Mgm = 0,
Mgt = 1, Mgt = 1,
@ -12,17 +21,45 @@ pub enum PcduSwitches {
#[derive(Debug, Copy, Clone, Serialize, Deserialize)] #[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum PcduRequest { pub enum PcduRequest {
SwitchDevice,
RequestSwitchInfo, RequestSwitchInfo,
} }
pub struct PcduModel { pub struct PcduModel {
pub switcher_list: Output<Vec<SwitchStateBinary>>, pub current_switch_info: Vec<SwitchStateBinary>,
pub mgm_switch: Output<SwitchState>, pub mgm_switch: Output<SwitchStateBinary>,
pub mgt_switch: Output<SwitchState>, pub mgt_switch: Output<SwitchStateBinary>,
pub reply_sender: mpsc::Sender<SimReply>,
} }
impl PcduModel { impl PcduModel {
pub async fn switch_device(&mut self, switch: PcduSwitches, switch_state: SwitchState) { pub fn new(reply_sender: mpsc::Sender<SimReply>) -> Self {
Self {
current_switch_info: vec![SwitchStateBinary::Off; 2],
mgm_switch: Output::new(),
mgt_switch: Output::new(),
reply_sender,
}
}
pub async fn request_switch_info(&mut self, _: (), scheduler: &Scheduler<Self>) {
scheduler
.schedule_event(
Duration::from_millis(SWITCH_INFO_DELAY_MS),
Self::send_switch_info,
(),
)
.expect("requesting switch info failed");
}
pub fn send_switch_info(&mut self) {
let switch_info = SwitchInfo(self.current_switch_info.clone());
let reply = SimReply::new(SimDevice::Pcdu, switch_info);
self.reply_sender.send(reply).unwrap();
}
pub async fn switch_device(&mut self, switch: PcduSwitches, switch_state: SwitchStateBinary) {
self.current_switch_info[switch as usize] = switch_state;
match switch { match switch {
PcduSwitches::Mgm => { PcduSwitches::Mgm => {
self.mgm_switch.send(switch_state).await; self.mgm_switch.send(switch_state).await;

View File

@ -9,8 +9,25 @@ pub enum SimDevice {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimRequest { pub struct SimRequest {
pub device: SimDevice, device: SimDevice,
pub request: String, request: String,
}
impl SimRequest {
pub fn new<T: Serialize>(device: SimDevice, reply: T) -> Self {
Self {
device,
request: serde_json::to_string(&reply).unwrap(),
}
}
pub fn device(&self) -> SimDevice {
self.device
}
pub fn request(&self) -> &String {
&self.request
}
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -19,6 +36,19 @@ pub struct SimReply {
pub reply: String, pub reply: String,
} }
impl SimReply {
pub fn new<T: Serialize>(device: SimDevice, reply: T) -> Self {
Self {
device,
reply: serde_json::to_string(&reply).unwrap(),
}
}
pub fn reply(&self) -> &String {
&self.reply
}
}
pub mod acs { pub mod acs {
use super::*; use super::*;

View File

@ -2,6 +2,8 @@ use acs::MagnetometerModel;
use asynchronix::simulation::{Mailbox, SimInit}; use asynchronix::simulation::{Mailbox, SimInit};
use asynchronix::time::{MonotonicTime, SystemClock}; use asynchronix::time::{MonotonicTime, SystemClock};
use controller::SimController; use controller::SimController;
use eps::PcduModel;
use satrs_minisim::{SimReply, SimRequest};
use std::sync::mpsc; use std::sync::mpsc;
use std::thread; use std::thread;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
@ -13,35 +15,57 @@ mod eps;
mod time; mod time;
mod udp; mod udp;
fn main() { #[derive(Debug, Copy, Clone, PartialEq, Eq)]
let shared_socket_addr = SharedSocketAddr::default(); pub enum ThreadingModel {
let (request_sender, request_receiver) = mpsc::channel(); Default = 0,
let (reply_sender, reply_receiver) = mpsc::channel(); 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. // Instantiate models and their mailboxes.
let mgm_sim = MagnetometerModel::new(Duration::from_millis(50), reply_sender.clone()); let mgm_model = MagnetometerModel::new(Duration::from_millis(50), reply_sender.clone());
let mgm_mailbox = Mailbox::new(); let mgm_mailbox = Mailbox::new();
let mgm_addr = mgm_mailbox.address(); let mgm_addr = mgm_mailbox.address();
let pcdu_mailbox = Mailbox::new(); let pcdu_mailbox = Mailbox::new();
let pcdu_addr = pcdu_mailbox.address(); let pcdu_addr = pcdu_mailbox.address();
// Instantiate the simulator let mut pcdu_model = PcduModel::new(reply_sender.clone());
let t0 = MonotonicTime::EPOCH;
let sys_clock = SystemClock::from_system_time(t0, SystemTime::now());
let simulation = SimInit::new().add_model(mgm_sim, mgm_mailbox).init(t0);
let mut sim_controller = SimController { pcdu_model
sys_clock, .mgm_switch
request_receiver, .connect(MagnetometerModel::switch_device, &mgm_addr);
simulation,
mgm_addr, // Instantiate the simulator
pcdu_addr, 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. // This thread schedules the simulator.
let sim_thread = thread::spawn(move || { let sim_thread = thread::spawn(move || {
sim_controller.run(t0); sim_ctrl.run(t0);
}); });
let mut server = UdpTcServer::new(request_sender, shared_socket_addr.clone()).unwrap(); let mut server = UdpTcServer::new(request_sender, shared_socket_addr.clone()).unwrap();
@ -69,6 +93,8 @@ mod tests {
SimDevice, SimReply, SimRequest, SimDevice, SimReply, SimRequest,
}; };
use crate::eps::PcduRequest;
use super::*; use super::*;
struct SimTestbench { struct SimTestbench {
@ -81,29 +107,12 @@ mod tests {
fn new() -> Self { fn new() -> Self {
let (request_sender, request_receiver) = mpsc::channel(); let (request_sender, request_receiver) = mpsc::channel();
let (reply_sender, reply_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 t0 = MonotonicTime::EPOCH;
let sys_clock = SystemClock::from_system_time(t0, SystemTime::now()); let sim_ctrl =
let simulation = SimInit::with_num_threads(1) create_sim_controller(ThreadingModel::Single, t0, reply_sender, request_receiver);
.add_model(mgm_sim, mgm_mailbox)
.init(t0);
Self { Self {
sim_controller: SimController { sim_controller: sim_ctrl,
sys_clock,
request_receiver,
simulation,
mgm_addr,
pcdu_addr,
},
reply_receiver, reply_receiver,
request_sender, request_sender,
} }
@ -140,10 +149,7 @@ mod tests {
fn test_basic_mgm_request() { fn test_basic_mgm_request() {
let mut sim_testbench = SimTestbench::new(); let mut sim_testbench = SimTestbench::new();
let mgm_request = MgmRequest::RequestSensorData; let mgm_request = MgmRequest::RequestSensorData;
let request = SimRequest { let request = SimRequest::new(SimDevice::Mgm, mgm_request);
device: SimDevice::Mgm,
request: serde_json::to_string(&mgm_request).unwrap(),
};
sim_testbench sim_testbench
.send_request(request) .send_request(request)
.expect("sending MGM request failed"); .expect("sending MGM request failed");
@ -161,5 +167,9 @@ mod tests {
} }
#[test] #[test]
fn test_basic_mgm_request_switched_on() {} 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);
}
} }

View File

@ -42,6 +42,15 @@ impl TryFrom<SwitchState> for SwitchStateBinary {
} }
} }
impl<T: Into<u64>> From<T> for SwitchStateBinary {
fn from(value: T) -> Self {
if value.into() == 0 {
return SwitchStateBinary::Off;
}
SwitchStateBinary::On
}
}
impl From<SwitchStateBinary> for SwitchState { impl From<SwitchStateBinary> for SwitchState {
fn from(value: SwitchStateBinary) -> Self { fn from(value: SwitchStateBinary) -> Self {
match value { match value {