First version of asynchronix based mini simulator #139
@ -7,7 +7,7 @@ use asynchronix::{
|
||||
use satrs::power::SwitchStateBinary;
|
||||
use satrs_minisim::{
|
||||
acs::{MgmReply, MgmSensorValues, MgtDipole, MgtHkSet, MgtReply, MGT_GEN_MAGNETIC_FIELD},
|
||||
SimReply, SimTarget,
|
||||
SimReply,
|
||||
};
|
||||
|
||||
use crate::time::current_millis;
|
||||
@ -54,14 +54,10 @@ impl MagnetometerModel {
|
||||
|
||||
pub async fn send_sensor_values(&mut self, _: (), scheduler: &Scheduler<Self>) {
|
||||
self.reply_sender
|
||||
.send(SimReply::new(
|
||||
SimTarget::Mgm,
|
||||
MgmReply {
|
||||
.send(SimReply::new(MgmReply {
|
||||
switch_state: self.switch_state,
|
||||
sensor_values: self
|
||||
.calculate_current_mgm_tuple(current_millis(scheduler.time())),
|
||||
},
|
||||
))
|
||||
sensor_values: self.calculate_current_mgm_tuple(current_millis(scheduler.time())),
|
||||
}))
|
||||
.expect("sending MGM sensor values failed");
|
||||
}
|
||||
|
||||
@ -149,12 +145,11 @@ impl MagnetorquerModel {
|
||||
}
|
||||
|
||||
pub fn send_housekeeping_data(&mut self) {
|
||||
let mgt_reply = MgtReply::Hk(MgtHkSet {
|
||||
self.reply_sender
|
||||
.send(SimReply::new(MgtReply::Hk(MgtHkSet {
|
||||
dipole: self.torque_dipole,
|
||||
torquing: self.torquing,
|
||||
});
|
||||
self.reply_sender
|
||||
.send(SimReply::new(SimTarget::Mgt, mgt_reply))
|
||||
})))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@ -186,7 +181,7 @@ pub mod tests {
|
||||
use satrs_minisim::{
|
||||
acs::{MgmReply, MgmRequest, MgtDipole, MgtHkSet, MgtReply, MgtRequest},
|
||||
eps::PcduSwitch,
|
||||
SimRequest, SimTarget,
|
||||
SerializableSimMsgPayload, SimMessageProvider, SimRequest, SimTarget,
|
||||
};
|
||||
|
||||
use crate::{eps::tests::switch_device_on, test_helpers::SimTestbench};
|
||||
@ -194,8 +189,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_basic_mgm_request() {
|
||||
let mut sim_testbench = SimTestbench::new();
|
||||
let mgm_request = MgmRequest::RequestSensorData;
|
||||
let request = SimRequest::new(SimTarget::Mgm, mgm_request);
|
||||
let request = SimRequest::new(MgmRequest::RequestSensorData);
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM request failed");
|
||||
@ -205,7 +199,7 @@ pub mod tests {
|
||||
assert!(sim_reply.is_some());
|
||||
let sim_reply = sim_reply.unwrap();
|
||||
assert_eq!(sim_reply.target(), SimTarget::Mgm);
|
||||
let reply: MgmReply = serde_json::from_str(sim_reply.reply())
|
||||
let reply = MgmReply::from_sim_message(&sim_reply)
|
||||
.expect("failed to deserialize MGM sensor values");
|
||||
assert_eq!(reply.switch_state, SwitchStateBinary::Off);
|
||||
assert_eq!(reply.sensor_values.x, 0.0);
|
||||
@ -218,8 +212,7 @@ pub mod tests {
|
||||
let mut sim_testbench = SimTestbench::new();
|
||||
switch_device_on(&mut sim_testbench, PcduSwitch::Mgm);
|
||||
|
||||
let mgm_request = MgmRequest::RequestSensorData;
|
||||
let mut request = SimRequest::new(SimTarget::Mgm, mgm_request);
|
||||
let mut request = SimRequest::new(MgmRequest::RequestSensorData);
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM request failed");
|
||||
@ -229,12 +222,11 @@ pub mod tests {
|
||||
assert!(sim_reply_res.is_some());
|
||||
let mut sim_reply = sim_reply_res.unwrap();
|
||||
assert_eq!(sim_reply.target(), SimTarget::Mgm);
|
||||
let first_reply: MgmReply = serde_json::from_str(sim_reply.reply())
|
||||
let first_reply = MgmReply::from_sim_message(&sim_reply)
|
||||
.expect("failed to deserialize MGM sensor values");
|
||||
let mgm_request = MgmRequest::RequestSensorData;
|
||||
sim_testbench.step_by(Duration::from_millis(50));
|
||||
|
||||
request = SimRequest::new(SimTarget::Mgm, mgm_request);
|
||||
request = SimRequest::new(MgmRequest::RequestSensorData);
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM request failed");
|
||||
@ -244,7 +236,7 @@ pub mod tests {
|
||||
assert!(sim_reply_res.is_some());
|
||||
sim_reply = sim_reply_res.unwrap();
|
||||
|
||||
let second_reply: MgmReply = serde_json::from_str(sim_reply.reply())
|
||||
let second_reply = MgmReply::from_sim_message(&sim_reply)
|
||||
.expect("failed to deserialize MGM sensor values");
|
||||
// Check that the values are changing.
|
||||
assert!(first_reply != second_reply);
|
||||
@ -253,8 +245,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_basic_mgt_request_is_off() {
|
||||
let mut sim_testbench = SimTestbench::new();
|
||||
let mgt_request = MgtRequest::RequestHk;
|
||||
let request = SimRequest::new(SimTarget::Mgt, mgt_request);
|
||||
let request = SimRequest::new(MgtRequest::RequestHk);
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM request failed");
|
||||
@ -268,8 +259,8 @@ pub mod tests {
|
||||
fn test_basic_mgt_request_is_on() {
|
||||
let mut sim_testbench = SimTestbench::new();
|
||||
switch_device_on(&mut sim_testbench, PcduSwitch::Mgt);
|
||||
let mgt_request = MgtRequest::RequestHk;
|
||||
let request = SimRequest::new(SimTarget::Mgt, mgt_request);
|
||||
let request = SimRequest::new(MgtRequest::RequestHk);
|
||||
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM request failed");
|
||||
@ -278,7 +269,7 @@ pub mod tests {
|
||||
let sim_reply_res = sim_testbench.try_receive_next_reply();
|
||||
assert!(sim_reply_res.is_some());
|
||||
let sim_reply = sim_reply_res.unwrap();
|
||||
let mgt_reply: MgtReply = serde_json::from_str(sim_reply.reply())
|
||||
let mgt_reply = MgtReply::from_sim_message(&sim_reply)
|
||||
.expect("failed to deserialize MGM sensor values");
|
||||
match mgt_reply {
|
||||
MgtReply::Hk(hk) => {
|
||||
@ -290,8 +281,7 @@ pub mod tests {
|
||||
}
|
||||
|
||||
fn check_mgt_hk(sim_testbench: &mut SimTestbench, expected_hk_set: MgtHkSet) {
|
||||
let mgt_request = MgtRequest::RequestHk;
|
||||
let request = SimRequest::new(SimTarget::Mgt, mgt_request);
|
||||
let request = SimRequest::new(MgtRequest::RequestHk);
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM request failed");
|
||||
@ -300,7 +290,7 @@ pub mod tests {
|
||||
let sim_reply_res = sim_testbench.try_receive_next_reply();
|
||||
assert!(sim_reply_res.is_some());
|
||||
let sim_reply = sim_reply_res.unwrap();
|
||||
let mgt_reply: MgtReply = serde_json::from_str(sim_reply.reply())
|
||||
let mgt_reply = MgtReply::from_sim_message(&sim_reply)
|
||||
.expect("failed to deserialize MGM sensor values");
|
||||
match mgt_reply {
|
||||
MgtReply::Hk(hk) => {
|
||||
@ -319,11 +309,10 @@ pub mod tests {
|
||||
y: 200,
|
||||
z: 1000,
|
||||
};
|
||||
let mgt_request = MgtRequest::ApplyTorque {
|
||||
let request = SimRequest::new(MgtRequest::ApplyTorque {
|
||||
duration: Duration::from_millis(100),
|
||||
dipole: commanded_dipole,
|
||||
};
|
||||
let request = SimRequest::new(SimTarget::Mgt, mgt_request);
|
||||
});
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM request failed");
|
||||
|
@ -7,7 +7,8 @@ use asynchronix::{
|
||||
use satrs_minisim::{
|
||||
acs::{MgmRequest, MgtRequest},
|
||||
eps::PcduRequest,
|
||||
RequestError, SimCtrlReply, SimCtrlRequest, SimReply, SimRequest, SimTarget,
|
||||
SerializableSimMsgPayload, SimCtrlReply, SimCtrlRequest, SimMessageProvider, SimReply,
|
||||
SimRequest, SimRequestError, SimTarget,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -86,19 +87,19 @@ impl SimController {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_ctrl_request(&mut self, request: &SimRequest) -> serde_json::Result<()> {
|
||||
let sim_ctrl_request: SimCtrlRequest = serde_json::from_str(request.request())?;
|
||||
fn handle_ctrl_request(&mut self, request: &SimRequest) -> Result<(), SimRequestError> {
|
||||
let sim_ctrl_request = SimCtrlRequest::from_sim_message(request)?;
|
||||
match sim_ctrl_request {
|
||||
SimCtrlRequest::Ping => {
|
||||
self.reply_sender
|
||||
.send(SimReply::new(SimTarget::SimCtrl, SimCtrlReply::Pong))
|
||||
.send(SimReply::new(SimCtrlReply::Pong))
|
||||
.expect("sending reply from sim controller failed");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn handle_mgm_request(&mut self, request: &SimRequest) -> serde_json::Result<()> {
|
||||
let mgm_request: MgmRequest = serde_json::from_str(request.request())?;
|
||||
fn handle_mgm_request(&mut self, request: &SimRequest) -> Result<(), SimRequestError> {
|
||||
let mgm_request = MgmRequest::from_sim_message(request)?;
|
||||
match mgm_request {
|
||||
MgmRequest::RequestSensorData => {
|
||||
self.simulation.send_event(
|
||||
@ -111,8 +112,8 @@ impl SimController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_pcdu_request(&mut self, request: &SimRequest) -> serde_json::Result<()> {
|
||||
let pcdu_request: PcduRequest = serde_json::from_str(request.request())?;
|
||||
fn handle_pcdu_request(&mut self, request: &SimRequest) -> Result<(), SimRequestError> {
|
||||
let pcdu_request = PcduRequest::from_sim_message(request)?;
|
||||
match pcdu_request {
|
||||
PcduRequest::RequestSwitchInfo => {
|
||||
self.simulation
|
||||
@ -129,8 +130,8 @@ impl SimController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_mgt_request(&mut self, request: &SimRequest) -> serde_json::Result<()> {
|
||||
let mgt_request: MgtRequest = serde_json::from_str(request.request())?;
|
||||
fn handle_mgt_request(&mut self, request: &SimRequest) -> Result<(), SimRequestError> {
|
||||
let mgt_request = MgtRequest::from_sim_message(request)?;
|
||||
match mgt_request {
|
||||
MgtRequest::ApplyTorque { duration, dipole } => self.simulation.send_event(
|
||||
MagnetorquerModel::apply_torque,
|
||||
@ -148,7 +149,7 @@ impl SimController {
|
||||
|
||||
fn handle_invalid_request_with_valid_target(
|
||||
&self,
|
||||
error: serde_json::Error,
|
||||
error: SimRequestError,
|
||||
request: &SimRequest,
|
||||
) {
|
||||
log::warn!(
|
||||
@ -157,10 +158,7 @@ impl SimController {
|
||||
error
|
||||
);
|
||||
self.reply_sender
|
||||
.send(SimReply::new(
|
||||
SimTarget::SimCtrl,
|
||||
SimCtrlReply::from(RequestError::TargetRequestMissmatch(request.clone())),
|
||||
))
|
||||
.send(SimReply::new(SimCtrlReply::from(error)))
|
||||
.expect("sending reply from sim controller failed");
|
||||
}
|
||||
}
|
||||
@ -174,8 +172,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_basic_ping() {
|
||||
let mut sim_testbench = SimTestbench::new();
|
||||
let sim_ctrl_request = SimCtrlRequest::Ping;
|
||||
let request = SimRequest::new(SimTarget::SimCtrl, sim_ctrl_request);
|
||||
let request = SimRequest::new(SimCtrlRequest::Ping);
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending sim ctrl request failed");
|
||||
@ -185,13 +182,8 @@ mod tests {
|
||||
assert!(sim_reply.is_some());
|
||||
let sim_reply = sim_reply.unwrap();
|
||||
assert_eq!(sim_reply.target(), SimTarget::SimCtrl);
|
||||
let reply: SimCtrlReply = serde_json::from_str(sim_reply.reply())
|
||||
let reply = SimCtrlReply::from_sim_message(&sim_reply)
|
||||
.expect("failed to deserialize MGM sensor values");
|
||||
assert_eq!(reply, SimCtrlReply::Pong);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_request() {
|
||||
// TODO: Implement this test. Check for the expected reply.
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use asynchronix::{
|
||||
use satrs::power::SwitchStateBinary;
|
||||
use satrs_minisim::{
|
||||
eps::{PcduReply, PcduSwitch, SwitchMap},
|
||||
SimReply, SimTarget,
|
||||
SimReply,
|
||||
};
|
||||
|
||||
pub const SWITCH_INFO_DELAY_MS: u64 = 10;
|
||||
@ -44,8 +44,7 @@ impl PcduModel {
|
||||
}
|
||||
|
||||
pub fn send_switch_info(&mut self) {
|
||||
let switch_info = PcduReply::SwitchInfo(self.switcher_map.clone());
|
||||
let reply = SimReply::new(SimTarget::Pcdu, switch_info);
|
||||
let reply = SimReply::new(PcduReply::SwitchInfo(self.switcher_map.clone()));
|
||||
self.reply_sender.send(reply).unwrap();
|
||||
}
|
||||
|
||||
@ -76,7 +75,9 @@ pub(crate) mod tests {
|
||||
use super::*;
|
||||
use std::time::Duration;
|
||||
|
||||
use satrs_minisim::{eps::PcduRequest, SimRequest, SimTarget};
|
||||
use satrs_minisim::{
|
||||
eps::PcduRequest, SerializableSimMsgPayload, SimMessageProvider, SimRequest, SimTarget,
|
||||
};
|
||||
|
||||
use crate::test_helpers::SimTestbench;
|
||||
|
||||
@ -85,11 +86,10 @@ pub(crate) mod tests {
|
||||
switch: PcduSwitch,
|
||||
target: SwitchStateBinary,
|
||||
) {
|
||||
let pcdu_request = PcduRequest::SwitchDevice {
|
||||
let request = SimRequest::new(PcduRequest::SwitchDevice {
|
||||
switch,
|
||||
state: target,
|
||||
};
|
||||
let request = SimRequest::new(SimTarget::Pcdu, pcdu_request);
|
||||
});
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM switch request failed");
|
||||
@ -113,8 +113,7 @@ pub(crate) mod tests {
|
||||
}
|
||||
|
||||
fn check_switch_state(sim_testbench: &mut SimTestbench, expected_switch_map: &SwitchMap) {
|
||||
let pcdu_request = PcduRequest::RequestSwitchInfo;
|
||||
let request = SimRequest::new(SimTarget::Pcdu, pcdu_request);
|
||||
let request = SimRequest::new(PcduRequest::RequestSwitchInfo);
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM request failed");
|
||||
@ -124,7 +123,7 @@ pub(crate) mod tests {
|
||||
assert!(sim_reply.is_some());
|
||||
let sim_reply = sim_reply.unwrap();
|
||||
assert_eq!(sim_reply.target(), SimTarget::Pcdu);
|
||||
let pcdu_reply: PcduReply = serde_json::from_str(&sim_reply.reply())
|
||||
let pcdu_reply = PcduReply::from_sim_message(&sim_reply)
|
||||
.expect("failed to deserialize PCDU switch info");
|
||||
match pcdu_reply {
|
||||
PcduReply::SwitchInfo(switch_map) => {
|
||||
@ -144,8 +143,7 @@ pub(crate) mod tests {
|
||||
#[test]
|
||||
fn test_pcdu_switcher_request() {
|
||||
let mut sim_testbench = SimTestbench::new();
|
||||
let pcdu_request = PcduRequest::RequestSwitchInfo;
|
||||
let request = SimRequest::new(SimTarget::Pcdu, pcdu_request);
|
||||
let request = SimRequest::new(PcduRequest::RequestSwitchInfo);
|
||||
sim_testbench
|
||||
.send_request(request)
|
||||
.expect("sending MGM request failed");
|
||||
@ -160,7 +158,7 @@ pub(crate) mod tests {
|
||||
assert!(sim_reply.is_some());
|
||||
let sim_reply = sim_reply.unwrap();
|
||||
assert_eq!(sim_reply.target(), SimTarget::Pcdu);
|
||||
let pcdu_reply: PcduReply = serde_json::from_str(&sim_reply.reply())
|
||||
let pcdu_reply = PcduReply::from_sim_message(&sim_reply)
|
||||
.expect("failed to deserialize PCDU switch info");
|
||||
match pcdu_reply {
|
||||
PcduReply::SwitchInfo(switch_map) => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SimTarget {
|
||||
@ -8,49 +8,101 @@ pub enum SimTarget {
|
||||
Pcdu,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SimMessage {
|
||||
pub target: SimTarget,
|
||||
pub payload: String,
|
||||
}
|
||||
|
||||
/// A generic simulation request type. Right now, the payload data is expected to be
|
||||
/// JSON, which might be changed in the future.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SimRequest {
|
||||
target: SimTarget,
|
||||
request: String,
|
||||
}
|
||||
|
||||
impl SimRequest {
|
||||
pub fn new<T: Serialize>(device: SimTarget, request: T) -> Self {
|
||||
Self {
|
||||
target: device,
|
||||
request: serde_json::to_string(&request).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn target(&self) -> SimTarget {
|
||||
self.target
|
||||
}
|
||||
|
||||
pub fn request(&self) -> &String {
|
||||
&self.request
|
||||
}
|
||||
inner: SimMessage,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SimMessageType {
|
||||
Request,
|
||||
Reply,
|
||||
}
|
||||
|
||||
/// Generic trait implemented by simulation request or reply payloads. It ties the request or
|
||||
/// reply to a specific target and provides an API which does boilerplate tasks like checking the
|
||||
/// validity of the target.
|
||||
pub trait SerializableSimMsgPayload<P: SimMessageProvider>:
|
||||
Serialize + DeserializeOwned + Sized
|
||||
{
|
||||
const TARGET: SimTarget;
|
||||
|
||||
fn from_sim_message(sim_message: &P) -> Result<Self, SimMessageError<P>> {
|
||||
if sim_message.target() == Self::TARGET {
|
||||
return Ok(serde_json::from_str(sim_message.payload())?);
|
||||
}
|
||||
Err(SimMessageError::TargetRequestMissmatch(sim_message.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SimMessageProvider: Serialize + DeserializeOwned + Clone + Sized {
|
||||
fn msg_type(&self) -> SimMessageType;
|
||||
fn target(&self) -> SimTarget;
|
||||
fn payload(&self) -> &String;
|
||||
fn from_raw_data(data: &[u8]) -> serde_json::Result<Self> {
|
||||
serde_json::from_slice(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl SimRequest {
|
||||
pub fn new<T: SerializableSimMsgPayload<SimRequest>>(serializable_request: T) -> Self {
|
||||
Self {
|
||||
inner: SimMessage {
|
||||
target: T::TARGET,
|
||||
payload: serde_json::to_string(&serializable_request).unwrap(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SimMessageProvider for SimRequest {
|
||||
fn target(&self) -> SimTarget {
|
||||
self.inner.target
|
||||
}
|
||||
fn payload(&self) -> &String {
|
||||
&self.inner.payload
|
||||
}
|
||||
|
||||
fn msg_type(&self) -> SimMessageType {
|
||||
SimMessageType::Request
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic simulation reply type. Right now, the payload data is expected to be
|
||||
/// JSON, which might be changed inthe future.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SimReply {
|
||||
target: SimTarget,
|
||||
reply: String,
|
||||
inner: SimMessage,
|
||||
}
|
||||
|
||||
impl SimReply {
|
||||
pub fn new<T: Serialize>(device: SimTarget, reply: T) -> Self {
|
||||
pub fn new<T: SerializableSimMsgPayload<SimReply>>(serializable_reply: T) -> Self {
|
||||
Self {
|
||||
target: device,
|
||||
reply: serde_json::to_string(&reply).unwrap(),
|
||||
inner: SimMessage {
|
||||
target: T::TARGET,
|
||||
payload: serde_json::to_string(&serializable_reply).unwrap(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn target(&self) -> SimTarget {
|
||||
self.target
|
||||
impl SimMessageProvider for SimReply {
|
||||
fn target(&self) -> SimTarget {
|
||||
self.inner.target
|
||||
}
|
||||
|
||||
pub fn reply(&self) -> &String {
|
||||
&self.reply
|
||||
fn payload(&self) -> &String {
|
||||
&self.inner.payload
|
||||
}
|
||||
fn msg_type(&self) -> SimMessageType {
|
||||
SimMessageType::Reply
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,19 +111,37 @@ pub enum SimCtrlRequest {
|
||||
Ping,
|
||||
}
|
||||
|
||||
impl SerializableSimMsgPayload<SimRequest> for SimCtrlRequest {
|
||||
const TARGET: SimTarget = SimTarget::SimCtrl;
|
||||
}
|
||||
|
||||
pub type SimReplyError = SimMessageError<SimReply>;
|
||||
pub type SimRequestError = SimMessageError<SimRequest>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum RequestError {
|
||||
TargetRequestMissmatch(SimRequest),
|
||||
pub enum SimMessageError<P> {
|
||||
SerdeJson(String),
|
||||
TargetRequestMissmatch(P),
|
||||
}
|
||||
|
||||
impl<P> From<serde_json::Error> for SimMessageError<P> {
|
||||
fn from(error: serde_json::Error) -> SimMessageError<P> {
|
||||
SimMessageError::SerdeJson(error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SimCtrlReply {
|
||||
Pong,
|
||||
InvalidRequest(RequestError),
|
||||
InvalidRequest(SimRequestError),
|
||||
}
|
||||
|
||||
impl From<RequestError> for SimCtrlReply {
|
||||
fn from(error: RequestError) -> Self {
|
||||
impl SerializableSimMsgPayload<SimReply> for SimCtrlReply {
|
||||
const TARGET: SimTarget = SimTarget::SimCtrl;
|
||||
}
|
||||
|
||||
impl From<SimRequestError> for SimCtrlReply {
|
||||
fn from(error: SimRequestError) -> Self {
|
||||
SimCtrlReply::InvalidRequest(error)
|
||||
}
|
||||
}
|
||||
@ -99,10 +169,18 @@ pub mod eps {
|
||||
RequestSwitchInfo,
|
||||
}
|
||||
|
||||
impl SerializableSimMsgPayload<SimRequest> for PcduRequest {
|
||||
const TARGET: SimTarget = SimTarget::Pcdu;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PcduReply {
|
||||
SwitchInfo(SwitchMap),
|
||||
}
|
||||
|
||||
impl SerializableSimMsgPayload<SimReply> for PcduReply {
|
||||
const TARGET: SimTarget = SimTarget::Pcdu;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod acs {
|
||||
@ -117,6 +195,10 @@ pub mod acs {
|
||||
RequestSensorData,
|
||||
}
|
||||
|
||||
impl SerializableSimMsgPayload<SimRequest> for MgmRequest {
|
||||
const TARGET: SimTarget = SimTarget::Mgm;
|
||||
}
|
||||
|
||||
// Normally, small magnetometers generate their output as a signed 16 bit raw format or something
|
||||
// similar which needs to be converted to a signed float value with physical units. We will
|
||||
// simplify this now and generate the signed float values directly.
|
||||
@ -133,6 +215,10 @@ pub mod acs {
|
||||
pub sensor_values: MgmSensorValues,
|
||||
}
|
||||
|
||||
impl SerializableSimMsgPayload<SimReply> for MgmReply {
|
||||
const TARGET: SimTarget = SimTarget::Mgm;
|
||||
}
|
||||
|
||||
pub const MGT_GEN_MAGNETIC_FIELD: MgmSensorValues = MgmSensorValues {
|
||||
x: 0.03,
|
||||
y: -0.03,
|
||||
@ -161,6 +247,10 @@ pub mod acs {
|
||||
RequestHk,
|
||||
}
|
||||
|
||||
impl SerializableSimMsgPayload<SimRequest> for MgtRequest {
|
||||
const TARGET: SimTarget = SimTarget::Mgt;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct MgtHkSet {
|
||||
pub dipole: MgtDipole,
|
||||
@ -173,6 +263,10 @@ pub mod acs {
|
||||
Nak(MgtRequestType),
|
||||
Hk(MgtHkSet),
|
||||
}
|
||||
|
||||
impl SerializableSimMsgPayload<SimReply> for MgtReply {
|
||||
const TARGET: SimTarget = SimTarget::Mgm;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod udp {
|
||||
@ -244,3 +338,46 @@ pub mod udp {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum DummyRequest {
|
||||
Ping,
|
||||
}
|
||||
|
||||
impl SerializableSimMsgPayload<SimRequest> for DummyRequest {
|
||||
const TARGET: SimTarget = SimTarget::SimCtrl;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum DummyReply {
|
||||
Pong,
|
||||
}
|
||||
|
||||
impl SerializableSimMsgPayload<SimReply> for DummyReply {
|
||||
const TARGET: SimTarget = SimTarget::SimCtrl;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_request() {
|
||||
let sim_request = SimRequest::new(DummyRequest::Ping);
|
||||
assert_eq!(sim_request.target(), SimTarget::SimCtrl);
|
||||
assert_eq!(sim_request.msg_type(), SimMessageType::Request);
|
||||
let dummy_request =
|
||||
DummyRequest::from_sim_message(&sim_request).expect("deserialization failed");
|
||||
assert_eq!(dummy_request, DummyRequest::Ping);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_reply() {
|
||||
let sim_reply = SimReply::new(DummyReply::Pong);
|
||||
assert_eq!(sim_reply.target(), SimTarget::SimCtrl);
|
||||
assert_eq!(sim_reply.msg_type(), SimMessageType::Reply);
|
||||
let dummy_request =
|
||||
DummyReply::from_sim_message(&sim_reply).expect("deserialization failed");
|
||||
assert_eq!(dummy_request, DummyReply::Pong);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use satrs_minisim::{SimReply, SimRequest};
|
||||
use satrs_minisim::{SimMessageProvider, SimReply, SimRequest};
|
||||
|
||||
// A UDP server which handles all TC received by a client application.
|
||||
pub struct SimUdpServer {
|
||||
@ -90,11 +90,7 @@ impl SimUdpServer {
|
||||
|
||||
self.sender_addr = Some(src);
|
||||
|
||||
// Convert the buffer into a string slice and print the message.
|
||||
let req_string = std::str::from_utf8(&self.req_buf[..bytes_read])
|
||||
.expect("Could not write buffer as string");
|
||||
log::info!("Received request from {}: {}", src, req_string);
|
||||
let sim_req: serde_json::Result<SimRequest> = serde_json::from_str(req_string);
|
||||
let sim_req = SimRequest::from_raw_data(&self.req_buf[..bytes_read]);
|
||||
if sim_req.is_err() {
|
||||
log::warn!(
|
||||
"received UDP request with invalid format: {}",
|
||||
@ -164,7 +160,7 @@ mod tests {
|
||||
use satrs_minisim::{
|
||||
eps::{PcduReply, PcduRequest},
|
||||
udp::{ReceptionError, SimUdpClient},
|
||||
SimCtrlReply, SimCtrlRequest, SimReply, SimRequest, SimTarget,
|
||||
SimCtrlReply, SimCtrlRequest, SimReply, SimRequest,
|
||||
};
|
||||
|
||||
use crate::eps::tests::get_all_off_switch_map;
|
||||
@ -274,7 +270,7 @@ mod tests {
|
||||
UdpTestbench::new(true, Some(SERVER_WAIT_TIME_MS), 10)
|
||||
.expect("could not create testbench");
|
||||
let server_thread = std::thread::spawn(move || udp_server.run());
|
||||
let sim_request = SimRequest::new(SimTarget::Pcdu, PcduRequest::RequestSwitchInfo);
|
||||
let sim_request = SimRequest::new(PcduRequest::RequestSwitchInfo);
|
||||
udp_testbench
|
||||
.send_request(&sim_request)
|
||||
.expect("sending request failed");
|
||||
@ -296,13 +292,10 @@ mod tests {
|
||||
.expect("could not create testbench");
|
||||
let server_thread = std::thread::spawn(move || udp_server.run());
|
||||
udp_testbench
|
||||
.send_request(&SimRequest::new(SimTarget::SimCtrl, SimCtrlRequest::Ping))
|
||||
.send_request(&SimRequest::new(SimCtrlRequest::Ping))
|
||||
.expect("sending request failed");
|
||||
|
||||
let sim_reply = SimReply::new(
|
||||
SimTarget::Pcdu,
|
||||
PcduReply::SwitchInfo(get_all_off_switch_map()),
|
||||
);
|
||||
let sim_reply = SimReply::new(PcduReply::SwitchInfo(get_all_off_switch_map()));
|
||||
udp_testbench.send_reply(&sim_reply);
|
||||
|
||||
udp_testbench.check_next_sim_reply(&sim_reply);
|
||||
@ -323,14 +316,11 @@ mod tests {
|
||||
// Send a ping so that the server knows the address of the client.
|
||||
// Do not check that the request arrives on the receiver side, is done by other test.
|
||||
udp_testbench
|
||||
.send_request(&SimRequest::new(SimTarget::SimCtrl, SimCtrlRequest::Ping))
|
||||
.send_request(&SimRequest::new(SimCtrlRequest::Ping))
|
||||
.expect("sending request failed");
|
||||
|
||||
// Send a reply to the server, ensure it gets forwarded to the client.
|
||||
let sim_reply = SimReply::new(
|
||||
SimTarget::Pcdu,
|
||||
PcduReply::SwitchInfo(get_all_off_switch_map()),
|
||||
);
|
||||
let sim_reply = SimReply::new(PcduReply::SwitchInfo(get_all_off_switch_map()));
|
||||
udp_testbench.send_reply(&sim_reply);
|
||||
std::thread::sleep(Duration::from_millis(SERVER_WAIT_TIME_MS));
|
||||
|
||||
@ -349,10 +339,7 @@ mod tests {
|
||||
let server_thread = std::thread::spawn(move || udp_server.run());
|
||||
|
||||
// Send a reply to the server. The client is not connected, so it won't get forwarded.
|
||||
let sim_reply = SimReply::new(
|
||||
SimTarget::Pcdu,
|
||||
PcduReply::SwitchInfo(get_all_off_switch_map()),
|
||||
);
|
||||
let sim_reply = SimReply::new(PcduReply::SwitchInfo(get_all_off_switch_map()));
|
||||
udp_testbench.send_reply(&sim_reply);
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
|
||||
@ -360,7 +347,7 @@ mod tests {
|
||||
|
||||
// Connect by sending a ping.
|
||||
udp_testbench
|
||||
.send_request(&SimRequest::new(SimTarget::SimCtrl, SimCtrlRequest::Ping))
|
||||
.send_request(&SimRequest::new(SimCtrlRequest::Ping))
|
||||
.expect("sending request failed");
|
||||
std::thread::sleep(Duration::from_millis(SERVER_WAIT_TIME_MS));
|
||||
|
||||
@ -379,7 +366,7 @@ mod tests {
|
||||
let server_thread = std::thread::spawn(move || udp_server.run());
|
||||
|
||||
// The server only caches up to 3 replies.
|
||||
let sim_reply = SimReply::new(SimTarget::SimCtrl, SimCtrlReply::Pong);
|
||||
let sim_reply = SimReply::new(SimCtrlReply::Pong);
|
||||
for _ in 0..4 {
|
||||
udp_testbench.send_reply(&sim_reply);
|
||||
}
|
||||
@ -389,7 +376,7 @@ mod tests {
|
||||
|
||||
// Connect by sending a ping.
|
||||
udp_testbench
|
||||
.send_request(&SimRequest::new(SimTarget::SimCtrl, SimCtrlRequest::Ping))
|
||||
.send_request(&SimRequest::new(SimCtrlRequest::Ping))
|
||||
.expect("sending request failed");
|
||||
std::thread::sleep(Duration::from_millis(SERVER_WAIT_TIME_MS));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user