new request/reponse API
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good
This commit is contained in:
@ -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 {
|
||||
@ -9,48 +9,100 @@ pub enum SimTarget {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SimRequest {
|
||||
target: SimTarget,
|
||||
request: String,
|
||||
pub struct SimMessage {
|
||||
pub target: SimTarget,
|
||||
pub payload: 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
|
||||
}
|
||||
/// 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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user