resue simulator for embedded examples
This commit is contained in:
@@ -7,6 +7,7 @@ members = [
|
||||
"examples/types",
|
||||
"examples/client",
|
||||
"examples/minisim",
|
||||
"examples/minisim-types",
|
||||
"satrs-shared",
|
||||
"tmtc-utils",
|
||||
"examples/embedded-client",
|
||||
|
||||
@@ -9,14 +9,13 @@ log = "0.4"
|
||||
fern = "0.7"
|
||||
humantime = "2"
|
||||
serde = { version = "1" }
|
||||
serde_json = "1"
|
||||
satrs = { path = "../../satrs" }
|
||||
satrs-example = { path = "../obsw-std" }
|
||||
satrs-minisim = { path = "../minisim" }
|
||||
minisim-types = { path = "../minisim-types" }
|
||||
types = { path = "../types" }
|
||||
spacepackets = { version = "0.18", default-features = false }
|
||||
bitbybit = "2"
|
||||
arbitrary-int = "2"
|
||||
ctrlc = { version = "3.5" }
|
||||
postcard = { version = "1" }
|
||||
postcard = { version = "1", features = ["alloc"] }
|
||||
anyhow = "1"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use anyhow::{Context as _, bail};
|
||||
use arbitrary_int::u11;
|
||||
use clap::Parser as _;
|
||||
use satrs_example::config::{OBSW_SERVER_ADDR, SERVER_PORT};
|
||||
use satrs_minisim::{
|
||||
use minisim_types::{
|
||||
SimCtrlReply, SimCtrlRequest, SimReply, SimRequest, SimRequestWithTime, acs::mgm,
|
||||
udp::SIM_CTRL_PORT,
|
||||
};
|
||||
use satrs_example::config::{OBSW_SERVER_ADDR, SERVER_PORT};
|
||||
use spacepackets::{CcsdsPacketIdAndPsc, SpacePacketHeader};
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket},
|
||||
@@ -611,10 +611,10 @@ fn inject_mgm_failure(target_id: types::ComponentId, fault: mgm::SpiFault) -> an
|
||||
|
||||
let mut reply_buf = [0u8; 4096];
|
||||
let ping = SimRequestWithTime::new_with_epoch_time(SimCtrlRequest::Ping);
|
||||
sim_socket.send_to(&serde_json::to_vec(&ping)?, sim_addr)?;
|
||||
sim_socket.send_to(&postcard::to_allocvec(&ping)?, sim_addr)?;
|
||||
match sim_socket.recv(&mut reply_buf) {
|
||||
Ok(len) => {
|
||||
let reply: SimReply = serde_json::from_slice(&reply_buf[..len])?;
|
||||
let reply: SimReply = postcard::from_bytes(&reply_buf[..len])?;
|
||||
if reply != SimReply::SimCtrl(SimCtrlReply::Pong) {
|
||||
bail!("unexpected reply while checking minisim connectivity: {reply:?}");
|
||||
}
|
||||
@@ -639,7 +639,7 @@ fn inject_mgm_failure(target_id: types::ComponentId, fault: mgm::SpiFault) -> an
|
||||
id,
|
||||
request: mgm::Request::SetSpiFault(fault),
|
||||
});
|
||||
sim_socket.send_to(&serde_json::to_vec(&request)?, sim_addr)?;
|
||||
sim_socket.send_to(&postcard::to_allocvec(&request)?, sim_addr)?;
|
||||
log::info!("injected SPI fault {fault:?} into minisim {target_id:?}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "minisim-types"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", default-features = false, features = ["derive"] }
|
||||
tai-time = { version = "1", default-features = false, features = ["serde"] }
|
||||
types = { path = "../types" }
|
||||
|
||||
[dev-dependencies]
|
||||
postcard = { version = "1", features = ["alloc"] }
|
||||
@@ -1,5 +1,7 @@
|
||||
use nexosim::time::MonotonicTime;
|
||||
#![no_std]
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tai_time::MonotonicTime;
|
||||
|
||||
use crate::{
|
||||
acs::{mgm, mgt},
|
||||
@@ -223,48 +225,11 @@ pub mod acs {
|
||||
z: value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_microtesla(values: SensorValuesMicroTesla) -> Self {
|
||||
let to_raw = |microtesla: f32| {
|
||||
(microtesla / (GAUSS_TO_MICROTESLA_FACTOR as f32 * FIELD_LSB_PER_GAUSS_4_SENS))
|
||||
.round() as i16
|
||||
};
|
||||
Self {
|
||||
x: to_raw(values.x),
|
||||
y: to_raw(values.y),
|
||||
z: to_raw(values.z),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Reply {
|
||||
pub fn new(
|
||||
switch_state: SwitchStateBinary,
|
||||
sensor_values: SensorValuesMicroTesla,
|
||||
fault_mode: SpiFaultMode,
|
||||
) -> Self {
|
||||
// An injected fault always wins. A switched off device reads back like an
|
||||
// undriven bus.
|
||||
let raw = match (fault_mode, switch_state) {
|
||||
(SpiFaultMode::AllZeros, _) => RawValues::splat(ALL_ZEROS_SENSOR_VAL),
|
||||
(SpiFaultMode::AllOnes, _) | (SpiFaultMode::None, SwitchStateBinary::Off) => {
|
||||
RawValues::splat(ALL_ONES_SENSOR_VAL)
|
||||
}
|
||||
(SpiFaultMode::None, SwitchStateBinary::On) => {
|
||||
RawValues::from_microtesla(sensor_values)
|
||||
}
|
||||
};
|
||||
Self {
|
||||
switch_state,
|
||||
sensor_values,
|
||||
raw,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod mgt {
|
||||
use std::time::Duration;
|
||||
use core::time::Duration;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -300,14 +265,16 @@ pub mod udp {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
mod tests {
|
||||
extern crate alloc;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_request_serde_roundtrip() {
|
||||
let sim_request = SimRequestWithTime::new_with_epoch_time(SimCtrlRequest::Ping);
|
||||
let json = serde_json::to_string(&sim_request).unwrap();
|
||||
let deserialized: SimRequestWithTime = serde_json::from_str(&json).unwrap();
|
||||
let bytes = postcard::to_allocvec(&sim_request).unwrap();
|
||||
let deserialized: SimRequestWithTime = postcard::from_bytes(&bytes).unwrap();
|
||||
assert_eq!(deserialized, sim_request);
|
||||
}
|
||||
|
||||
@@ -315,8 +282,8 @@ pub mod tests {
|
||||
fn test_reply_serde_roundtrip() {
|
||||
let sim_reply = SimReply::from(SimCtrlReply::Pong);
|
||||
assert_eq!(sim_reply.component(), ComponentId::SimCtrl);
|
||||
let json = serde_json::to_string(&sim_reply).unwrap();
|
||||
let deserialized: SimReply = serde_json::from_str(&json).unwrap();
|
||||
let bytes = postcard::to_allocvec(&sim_reply).unwrap();
|
||||
let deserialized: SimReply = postcard::from_bytes(&bytes).unwrap();
|
||||
assert_eq!(deserialized, sim_reply);
|
||||
}
|
||||
}
|
||||
@@ -7,18 +7,18 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
postcard = { version = "1", features = ["alloc"] }
|
||||
log = "0.4"
|
||||
thiserror = "2"
|
||||
fern = "0.7"
|
||||
strum = { version = "0.28", features = ["derive"] }
|
||||
num_enum = "0.7"
|
||||
humantime = "2"
|
||||
tai-time = { version = "0.3", features = ["serde"] }
|
||||
nexosim = "1"
|
||||
|
||||
satrs = { path = "../../satrs" }
|
||||
types = { path = "../types" }
|
||||
minisim-types = { path = "../minisim-types" }
|
||||
|
||||
[dev-dependencies]
|
||||
delegate = "0.13"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::f32::consts::PI;
|
||||
|
||||
use minisim_types::{acs::mgm, SimReply};
|
||||
use nexosim::{
|
||||
model::{Context, Model},
|
||||
ports::Output,
|
||||
};
|
||||
use satrs_minisim::{acs::mgm, SimReply};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use types::pcdu::SwitchStateBinary;
|
||||
|
||||
@@ -59,7 +59,7 @@ impl MgmModel {
|
||||
pub async fn send_sensor_values(&mut self, _: (), cx: &Context<Self>) {
|
||||
let reply = SimReply::Mgm {
|
||||
id: self.id,
|
||||
reply: mgm::Reply::new(
|
||||
reply: create_reply(
|
||||
self.switch_state,
|
||||
self.calculate_current_mgm_tuple(current_millis(cx.time())),
|
||||
self.spi_fault.mode,
|
||||
@@ -98,11 +98,46 @@ impl MgmModel {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds the reply of the simulated LIS3MDL, including the raw register values.
|
||||
fn create_reply(
|
||||
switch_state: SwitchStateBinary,
|
||||
sensor_values: mgm::SensorValuesMicroTesla,
|
||||
fault_mode: mgm::SpiFaultMode,
|
||||
) -> mgm::Reply {
|
||||
// An injected fault always wins. A switched off device reads back like an undriven bus.
|
||||
let raw = match (fault_mode, switch_state) {
|
||||
(mgm::SpiFaultMode::AllZeros, _) => mgm::RawValues::splat(mgm::ALL_ZEROS_SENSOR_VAL),
|
||||
(mgm::SpiFaultMode::AllOnes, _) | (mgm::SpiFaultMode::None, SwitchStateBinary::Off) => {
|
||||
mgm::RawValues::splat(mgm::ALL_ONES_SENSOR_VAL)
|
||||
}
|
||||
(mgm::SpiFaultMode::None, SwitchStateBinary::On) => {
|
||||
raw_values_from_microtesla(sensor_values)
|
||||
}
|
||||
};
|
||||
mgm::Reply {
|
||||
switch_state,
|
||||
sensor_values,
|
||||
raw,
|
||||
}
|
||||
}
|
||||
|
||||
fn raw_values_from_microtesla(values: mgm::SensorValuesMicroTesla) -> mgm::RawValues {
|
||||
let to_raw = |microtesla: f32| {
|
||||
(microtesla / (mgm::GAUSS_TO_MICROTESLA_FACTOR as f32 * mgm::FIELD_LSB_PER_GAUSS_4_SENS))
|
||||
.round() as i16
|
||||
};
|
||||
mgm::RawValues {
|
||||
x: to_raw(values.x),
|
||||
y: to_raw(values.y),
|
||||
z: to_raw(values.z),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
||||
use satrs_minisim::{acs::mgm, SimReply, SimRequest};
|
||||
use minisim_types::{acs::mgm, SimReply, SimRequest};
|
||||
use types::pcdu::{SwitchId, SwitchStateBinary};
|
||||
|
||||
use crate::{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use minisim_types::{
|
||||
acs::{mgm, mgt},
|
||||
SimReply,
|
||||
};
|
||||
use nexosim::{
|
||||
model::{schedulable, Context, Model},
|
||||
ports::Output,
|
||||
};
|
||||
use satrs_minisim::{
|
||||
acs::{mgm, mgt},
|
||||
SimReply,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use types::pcdu::SwitchStateBinary;
|
||||
@@ -109,7 +109,7 @@ impl MgtModel {
|
||||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
||||
use satrs_minisim::{
|
||||
use minisim_types::{
|
||||
acs::{mgm, mgt},
|
||||
eps::PcduRequest,
|
||||
SimReply, SimRequest, SimRequestWithTime,
|
||||
|
||||
@@ -3,16 +3,16 @@ use std::{
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use minisim_types::{
|
||||
acs::{mgm, mgt},
|
||||
eps::PcduRequest,
|
||||
SimCtrlReply, SimCtrlRequest, SimReply, SimRequest, SimRequestWithTime,
|
||||
};
|
||||
use nexosim::{
|
||||
ports::{event_queue, EventQueueReader, EventSinkReader, EventSource, SinkState},
|
||||
simulation::{EventId, ExecutionError, Mailbox, SimInit, Simulation},
|
||||
time::{Clock, Deadline, MonotonicTime, SystemClock},
|
||||
};
|
||||
use satrs_minisim::{
|
||||
acs::{mgm, mgt},
|
||||
eps::PcduRequest,
|
||||
SimCtrlReply, SimCtrlRequest, SimReply, SimRequest, SimRequestWithTime,
|
||||
};
|
||||
use types::pcdu::{SwitchId, SwitchStateBinary};
|
||||
|
||||
use crate::{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use minisim_types::{eps::PcduReply, SimReply};
|
||||
use nexosim::{
|
||||
model::{schedulable, Context, Model},
|
||||
ports::Output,
|
||||
};
|
||||
use satrs_minisim::{eps::PcduReply, SimReply};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use types::pcdu::{SwitchId, SwitchMapBinary, SwitchMapBinaryWrapper, SwitchStateBinary};
|
||||
|
||||
@@ -76,7 +76,7 @@ pub(crate) mod tests {
|
||||
use super::*;
|
||||
use std::time::Duration;
|
||||
|
||||
use satrs_minisim::{eps::PcduRequest, SimRequestWithTime};
|
||||
use minisim_types::{eps::PcduRequest, SimRequestWithTime};
|
||||
use types::pcdu::SwitchMapBinary;
|
||||
|
||||
use crate::test_helpers::SimTestbench;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use controller::{SimController, ThreadingModel};
|
||||
use minisim_types::udp::SIM_CTRL_PORT;
|
||||
use nexosim::time::MonotonicTime;
|
||||
use satrs_minisim::udp::SIM_CTRL_PORT;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use udp::SimUdpServer;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use delegate::delegate;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use minisim_types::{SimReply, SimRequest, SimRequestWithTime};
|
||||
use nexosim::{
|
||||
simulation::ExecutionError,
|
||||
time::{Deadline, MonotonicTime},
|
||||
};
|
||||
use satrs_minisim::{SimReply, SimRequest, SimRequestWithTime};
|
||||
|
||||
use crate::controller::{SimController, ThreadingModel};
|
||||
|
||||
|
||||
+11
-12
@@ -6,7 +6,7 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use satrs_minisim::{SimReply, SimRequestWithTime};
|
||||
use minisim_types::{SimReply, SimRequestWithTime};
|
||||
|
||||
// A UDP server which handles all TC received by a client application.
|
||||
pub struct SimUdpServer {
|
||||
@@ -89,7 +89,7 @@ impl SimUdpServer {
|
||||
|
||||
self.sender_addr = Some(src);
|
||||
|
||||
let sim_req = serde_json::from_slice::<SimRequestWithTime>(&self.req_buf[..bytes_read]);
|
||||
let sim_req = postcard::from_bytes::<SimRequestWithTime>(&self.req_buf[..bytes_read]);
|
||||
if let Err(e) = sim_req {
|
||||
log::warn!("received UDP request with invalid format: {}", e);
|
||||
return processed_requests;
|
||||
@@ -130,9 +130,7 @@ impl SimUdpServer {
|
||||
let next_reply_to_send = self.reply_queue.pop_front().unwrap();
|
||||
self.socket
|
||||
.send_to(
|
||||
serde_json::to_string(&next_reply_to_send)
|
||||
.unwrap()
|
||||
.as_bytes(),
|
||||
&postcard::to_allocvec(&next_reply_to_send).unwrap(),
|
||||
self.sender_addr.unwrap(),
|
||||
)
|
||||
.expect("sending reply failed");
|
||||
@@ -154,7 +152,7 @@ mod tests {
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use satrs_minisim::{
|
||||
use minisim_types::{
|
||||
eps::{PcduReply, PcduRequest},
|
||||
SimCtrlReply, SimCtrlRequest, SimReply, SimRequestWithTime,
|
||||
};
|
||||
@@ -171,8 +169,8 @@ mod tests {
|
||||
pub enum ReceptionError {
|
||||
#[error("IO error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("Serde JSON error: {0}")]
|
||||
SerdeJson(#[from] serde_json::Error),
|
||||
#[error("postcard error: {0}")]
|
||||
Postcard(#[from] postcard::Error),
|
||||
}
|
||||
|
||||
pub struct SimUdpTestClient {
|
||||
@@ -203,7 +201,8 @@ mod tests {
|
||||
|
||||
pub fn send_request(&self, sim_request: &SimRequestWithTime) -> std::io::Result<usize> {
|
||||
self.socket.send(
|
||||
&serde_json::to_vec(sim_request).expect("conversion of request to vector failed"),
|
||||
&postcard::to_allocvec(sim_request)
|
||||
.expect("conversion of request to vector failed"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -213,7 +212,7 @@ mod tests {
|
||||
|
||||
pub fn recv_sim_reply(&mut self) -> Result<SimReply, ReceptionError> {
|
||||
let read_len = self.recv_raw()?;
|
||||
Ok(serde_json::from_slice(&self.reply_buf[0..read_len])?)
|
||||
Ok(postcard::from_bytes(&self.reply_buf[0..read_len])?)
|
||||
}
|
||||
}
|
||||
struct UdpTestbench {
|
||||
@@ -302,8 +301,8 @@ mod tests {
|
||||
panic!("unexpected request server error: {e}");
|
||||
}
|
||||
}
|
||||
ReceptionError::SerdeJson(json_error) => {
|
||||
panic!("unexpected JSON error: {json_error}");
|
||||
ReceptionError::Postcard(postcard_error) => {
|
||||
panic!("unexpected postcard error: {postcard_error}");
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -22,14 +22,13 @@ derive-new = "0.7"
|
||||
cfg-if = "1"
|
||||
arbitrary-int = "2"
|
||||
bitbybit = "2"
|
||||
postcard = "1"
|
||||
postcard = { version = "1", features = ["alloc"] }
|
||||
ctrlc = "3"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
||||
satrs = { path = "../../satrs", features = ["test_util"] }
|
||||
types = { path = "../types" }
|
||||
satrs-minisim = { path = "../minisim" }
|
||||
minisim-types = { path = "../minisim-types" }
|
||||
satrs-mib = { path = "../../satrs-mib" }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use minisim_types::acs::mgm as sim_mgm;
|
||||
use minisim_types::acs::mgm::{FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR};
|
||||
use minisim_types::{SimReply, SimRequest, SimRequestWithTime};
|
||||
use satrs::fdir::{FaultCounterStd, FaultResponse, RecoveryEvent, RecoveryFdir};
|
||||
use satrs::health::HealthTableMapSync;
|
||||
use satrs::spacepackets::CcsdsPacketIdAndPsc;
|
||||
use satrs_example::{HkHelperSingleSet, TimestampHelper, TmtcQueues};
|
||||
use satrs_minisim::acs::mgm as sim_mgm;
|
||||
use satrs_minisim::acs::mgm::{FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR};
|
||||
use satrs_minisim::{SimReply, SimRequest, SimRequestWithTime};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
@@ -652,9 +652,9 @@ mod tests {
|
||||
};
|
||||
|
||||
use arbitrary_int::u11;
|
||||
use minisim_types::acs::mgm as sim_mgm;
|
||||
use satrs::health::{HealthState, HealthTableProvider};
|
||||
use satrs::spacepackets::SpacePacketHeader;
|
||||
use satrs_minisim::acs::mgm as sim_mgm;
|
||||
use types::{
|
||||
Apid, ComponentId, TcHeader,
|
||||
acs::mgm::request::HkRequest,
|
||||
|
||||
@@ -2,10 +2,10 @@ use std::collections::VecDeque;
|
||||
use std::sync::mpsc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use minisim_types::acs::mgt as sim_mgt;
|
||||
use minisim_types::{SimReply, SimRequestWithTime};
|
||||
use satrs::spacepackets::CcsdsPacketIdAndPsc;
|
||||
use satrs_example::{HkHelperSingleSet, TmtcQueues};
|
||||
use satrs_minisim::acs::mgt as sim_mgt;
|
||||
use satrs_minisim::{SimReply, SimRequestWithTime};
|
||||
use types::acs::mgt::{
|
||||
self, HkSet,
|
||||
request::{ModeRequest, Request},
|
||||
|
||||
@@ -5,13 +5,13 @@ use std::{
|
||||
};
|
||||
|
||||
use derive_new::new;
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use satrs::spacepackets::CcsdsPacketIdAndPsc;
|
||||
use satrs_example::TimestampHelper;
|
||||
use satrs_minisim::{
|
||||
use minisim_types::{
|
||||
SimReply, SimRequestWithTime,
|
||||
eps::{PcduReply, PcduRequest},
|
||||
};
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use satrs::spacepackets::CcsdsPacketIdAndPsc;
|
||||
use satrs_example::TimestampHelper;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::IntoEnumIterator as _;
|
||||
use types::{
|
||||
@@ -134,7 +134,7 @@ impl SerialInterface for SerialInterfaceToSim {
|
||||
type Error = ();
|
||||
|
||||
fn send(&self, data: &[u8]) -> Result<(), Self::Error> {
|
||||
let request: PcduRequest = serde_json::from_slice(data).expect("expected a PCDU request");
|
||||
let request: PcduRequest = postcard::from_bytes(data).expect("expected a PCDU request");
|
||||
self.sim_request_tx
|
||||
.send(SimRequestWithTime::new_with_epoch_time(request))
|
||||
.expect("failed to send request to simulation");
|
||||
@@ -148,8 +148,8 @@ impl SerialInterface for SerialInterfaceToSim {
|
||||
loop {
|
||||
match self.sim_reply_rx.try_recv() {
|
||||
Ok(reply) => {
|
||||
let reply = serde_json::to_string(&reply).unwrap();
|
||||
f(reply.as_bytes());
|
||||
let reply = postcard::to_allocvec(&reply).unwrap();
|
||||
f(&reply);
|
||||
}
|
||||
Err(e) => match e {
|
||||
mpsc::TryRecvError::Empty => break,
|
||||
@@ -175,11 +175,13 @@ impl SerialInterface for SerialInterfaceDummy {
|
||||
type Error = ();
|
||||
|
||||
fn send(&self, data: &[u8]) -> Result<(), Self::Error> {
|
||||
let pcdu_req: PcduRequest = serde_json::from_slice(data).unwrap();
|
||||
let pcdu_req: PcduRequest = postcard::from_bytes(data).unwrap();
|
||||
let switch_map_mut = &mut self.switch_map.borrow_mut().0;
|
||||
match pcdu_req {
|
||||
PcduRequest::SwitchDevice { switch, state } => {
|
||||
switch_map_mut.insert(switch, state);
|
||||
switch_map_mut
|
||||
.insert(switch, state)
|
||||
.expect("switch map capacity exceeded");
|
||||
}
|
||||
PcduRequest::RequestSwitchInfo => {
|
||||
let mut reply_deque_mut = self.reply_deque.borrow_mut();
|
||||
@@ -199,8 +201,8 @@ impl SerialInterface for SerialInterfaceDummy {
|
||||
return Ok(());
|
||||
}
|
||||
loop {
|
||||
let reply = self.get_next_reply_as_string();
|
||||
f(reply.as_bytes());
|
||||
let reply = self.next_reply_serialized();
|
||||
f(&reply);
|
||||
if self.reply_queue_empty() {
|
||||
break;
|
||||
}
|
||||
@@ -210,10 +212,10 @@ impl SerialInterface for SerialInterfaceDummy {
|
||||
}
|
||||
|
||||
impl SerialInterfaceDummy {
|
||||
fn get_next_reply_as_string(&self) -> String {
|
||||
fn next_reply_serialized(&self) -> Vec<u8> {
|
||||
let mut reply_deque_mut = self.reply_deque.borrow_mut();
|
||||
let next_reply = reply_deque_mut.pop_front().unwrap();
|
||||
serde_json::to_string(&next_reply).unwrap()
|
||||
postcard::to_allocvec(&next_reply).unwrap()
|
||||
}
|
||||
|
||||
fn reply_queue_empty(&self) -> bool {
|
||||
@@ -430,8 +432,8 @@ impl<ComInterface: SerialInterface> PcduHandler<ComInterface> {
|
||||
|
||||
pub fn handle_periodic_commands(&self) {
|
||||
let pcdu_req = PcduRequest::RequestSwitchInfo;
|
||||
let pcdu_req_ser = serde_json::to_string(&pcdu_req).unwrap();
|
||||
if let Err(_e) = self.com_interface.send(pcdu_req_ser.as_bytes()) {
|
||||
let pcdu_req_ser = postcard::to_allocvec(&pcdu_req).unwrap();
|
||||
if let Err(_e) = self.com_interface.send(&pcdu_req_ser) {
|
||||
log::warn!("polling PCDU switch info failed");
|
||||
if let Err(e) = self.event_tx.send(pcdu::Event::SerialCommError) {
|
||||
log::warn!("failed to send comm error event: {}", e);
|
||||
@@ -477,9 +479,9 @@ impl<ComInterface: SerialInterface> PcduHandler<ComInterface> {
|
||||
switch: switch_id,
|
||||
state,
|
||||
};
|
||||
let pcdu_req_ser = serde_json::to_string(&pcdu_req).unwrap();
|
||||
let pcdu_req_ser = postcard::to_allocvec(&pcdu_req).unwrap();
|
||||
self.com_interface
|
||||
.send(pcdu_req_ser.as_bytes())
|
||||
.send(&pcdu_req_ser)
|
||||
.expect("failed to send switch request to PCDU");
|
||||
}
|
||||
|
||||
@@ -502,7 +504,7 @@ impl<ComInterface: SerialInterface> PcduHandler<ComInterface> {
|
||||
|
||||
pub fn poll_and_handle_replies(&mut self) {
|
||||
if let Err(e) = self.com_interface.try_recv_replies(|reply| {
|
||||
let sim_reply: SimReply = serde_json::from_slice(reply).expect("invalid reply format");
|
||||
let sim_reply: SimReply = postcard::from_bytes(reply).expect("invalid reply format");
|
||||
let SimReply::Pcdu(pcdu_reply) = sim_reply else {
|
||||
log::warn!("unexpected PCDU SIM reply: {sim_reply:?}");
|
||||
return;
|
||||
@@ -552,7 +554,7 @@ mod tests {
|
||||
pub struct SerialInterfaceTest {
|
||||
pub inner: SerialInterfaceDummy,
|
||||
pub send_queue: RefCell<VecDeque<Vec<u8>>>,
|
||||
pub reply_queue: RefCell<VecDeque<String>>,
|
||||
pub reply_queue: RefCell<VecDeque<Vec<u8>>>,
|
||||
/// Makes the next `send` call fail, to exercise comm-error handling.
|
||||
pub fail_next_send: RefCell<bool>,
|
||||
}
|
||||
@@ -577,9 +579,9 @@ mod tests {
|
||||
return Ok(());
|
||||
}
|
||||
loop {
|
||||
let reply = self.inner.get_next_reply_as_string();
|
||||
let reply = self.inner.next_reply_serialized();
|
||||
self.reply_queue.borrow_mut().push_back(reply.clone());
|
||||
f(reply.as_bytes());
|
||||
f(&reply);
|
||||
if self.inner.reply_queue_empty() {
|
||||
break;
|
||||
}
|
||||
@@ -635,7 +637,7 @@ mod tests {
|
||||
assert_eq!(send_queue_mut.len(), expected_queue_len);
|
||||
let packet_sent = send_queue_mut.pop_front().unwrap();
|
||||
drop(send_queue_mut);
|
||||
let pcdu_req: PcduRequest = serde_json::from_slice(&packet_sent).unwrap();
|
||||
let pcdu_req: PcduRequest = postcard::from_bytes(&packet_sent).unwrap();
|
||||
assert_eq!(pcdu_req, PcduRequest::RequestSwitchInfo);
|
||||
}
|
||||
|
||||
@@ -650,7 +652,7 @@ mod tests {
|
||||
assert_eq!(send_queue_mut.len(), expected_queue_len);
|
||||
let packet_sent = send_queue_mut.pop_front().unwrap();
|
||||
drop(send_queue_mut);
|
||||
let pcdu_req: PcduRequest = serde_json::from_slice(&packet_sent).unwrap();
|
||||
let pcdu_req: PcduRequest = postcard::from_bytes(&packet_sent).unwrap();
|
||||
assert_eq!(
|
||||
pcdu_req,
|
||||
PcduRequest::SwitchDevice {
|
||||
@@ -669,7 +671,7 @@ mod tests {
|
||||
let mut reply_received_mut = self.handler.com_interface.reply_queue.borrow_mut();
|
||||
assert_eq!(reply_received_mut.len(), expected_queue_len);
|
||||
let reply_received = reply_received_mut.pop_front().unwrap();
|
||||
let sim_reply: SimReply = serde_json::from_str(&reply_received).unwrap();
|
||||
let sim_reply: SimReply = postcard::from_bytes(&reply_received).unwrap();
|
||||
assert_eq!(
|
||||
sim_reply,
|
||||
SimReply::Pcdu(PcduReply::SwitchInfo(expected_map))
|
||||
|
||||
@@ -5,9 +5,9 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use minisim_types::{ComponentId, SimReply, SimRequestWithTime, udp::SIM_CTRL_PORT};
|
||||
use minisim_types::{SimCtrlReply, SimCtrlRequest};
|
||||
use satrs::HandlingStatus;
|
||||
use satrs_minisim::{ComponentId, SimReply, SimRequestWithTime, udp::SIM_CTRL_PORT};
|
||||
use satrs_minisim::{SimCtrlReply, SimCtrlRequest};
|
||||
|
||||
struct SimReplyMap(pub HashMap<ComponentId, mpsc::Sender<SimReply>>);
|
||||
|
||||
@@ -35,10 +35,10 @@ pub enum SimClientCreationError {
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("timeout when trying to connect to sim UDP server")]
|
||||
Timeout,
|
||||
#[error("invalid ping reply when trying connection to UDP sim server")]
|
||||
InvalidReplyJsonError(#[from] serde_json::Error),
|
||||
#[error("invalid ping reply when trying connection to UDP sim server: {0}")]
|
||||
InvalidReply(#[from] postcard::Error),
|
||||
#[error("invalid sim reply, not pong reply as expected: {0:?}")]
|
||||
ReplyIsNotPong(SimReply),
|
||||
ReplyIsNotPong(Box<SimReply>),
|
||||
}
|
||||
|
||||
pub struct SimClientUdp {
|
||||
@@ -74,14 +74,14 @@ impl SimClientUdp {
|
||||
reply_buf: &mut [u8],
|
||||
) -> Result<(), SimClientCreationError> {
|
||||
let sim_req = SimRequestWithTime::new_with_epoch_time(SimCtrlRequest::Ping);
|
||||
let sim_req_json = serde_json::to_string(&sim_req).expect("failed to serialize SimRequest");
|
||||
udp_client.send_to(sim_req_json.as_bytes(), simulator_addr)?;
|
||||
let sim_req_raw = postcard::to_allocvec(&sim_req).expect("failed to serialize SimRequest");
|
||||
udp_client.send_to(&sim_req_raw, simulator_addr)?;
|
||||
match udp_client.recv(reply_buf) {
|
||||
Ok(reply_len) => {
|
||||
let sim_reply: SimReply = serde_json::from_slice(&reply_buf[0..reply_len])?;
|
||||
let sim_reply: SimReply = postcard::from_bytes(&reply_buf[0..reply_len])?;
|
||||
match sim_reply {
|
||||
SimReply::SimCtrl(SimCtrlReply::Pong) => Ok(()),
|
||||
_ => Err(SimClientCreationError::ReplyIsNotPong(sim_reply)),
|
||||
_ => Err(SimClientCreationError::ReplyIsNotPong(Box::new(sim_reply))),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -102,12 +102,9 @@ impl SimClientUdp {
|
||||
loop {
|
||||
match self.sim_request_rx.try_recv() {
|
||||
Ok(request) => {
|
||||
let request_json =
|
||||
serde_json::to_string(&request).expect("failed to serialize SimRequest");
|
||||
if let Err(e) = self
|
||||
.udp_client
|
||||
.send_to(request_json.as_bytes(), self.simulator_addr)
|
||||
{
|
||||
let request_raw =
|
||||
postcard::to_allocvec(&request).expect("failed to serialize SimRequest");
|
||||
if let Err(e) = self.udp_client.send_to(&request_raw, self.simulator_addr) {
|
||||
log::error!("error sending data to UDP SIM server: {e}");
|
||||
break;
|
||||
} else {
|
||||
@@ -129,8 +126,8 @@ impl SimClientUdp {
|
||||
match self.udp_client.recv(&mut self.reply_buf) {
|
||||
Ok(recvd_bytes) => {
|
||||
no_data_from_udp_server_received = false;
|
||||
let sim_reply_result: serde_json::Result<SimReply> =
|
||||
serde_json::from_slice(&self.reply_buf[0..recvd_bytes]);
|
||||
let sim_reply_result: postcard::Result<SimReply> =
|
||||
postcard::from_bytes(&self.reply_buf[0..recvd_bytes]);
|
||||
match sim_reply_result {
|
||||
Ok(sim_reply) => {
|
||||
if let Some(sender) = self.reply_map.0.get(&sim_reply.component()) {
|
||||
@@ -185,7 +182,7 @@ pub mod tests {
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use satrs_minisim::{
|
||||
use minisim_types::{
|
||||
ComponentId, SimCtrlReply, SimCtrlRequest, SimReply, SimRequest, SimRequestWithTime,
|
||||
eps::{PcduReply, PcduRequest},
|
||||
};
|
||||
@@ -234,10 +231,10 @@ pub mod tests {
|
||||
loop {
|
||||
match self.reply_rx.try_recv() {
|
||||
Ok(sim_reply) => {
|
||||
let sim_reply_json = serde_json::to_string(&sim_reply)
|
||||
let sim_reply_raw = postcard::to_allocvec(&sim_reply)
|
||||
.expect("failed to serialize SimReply");
|
||||
self.udp_server
|
||||
.send_to(sim_reply_json.as_bytes(), last_sender)
|
||||
.send_to(&sim_reply_raw, last_sender)
|
||||
.expect("failed to send reply to client from UDP server");
|
||||
no_sim_replies_handled = false;
|
||||
}
|
||||
@@ -255,17 +252,17 @@ pub mod tests {
|
||||
match self.udp_server.recv_from(&mut self.recv_buf) {
|
||||
Ok((read_bytes, from)) => {
|
||||
let sim_request: SimRequestWithTime =
|
||||
serde_json::from_slice(&self.recv_buf[0..read_bytes])
|
||||
postcard::from_bytes(&self.recv_buf[0..read_bytes])
|
||||
.expect("failed to deserialize SimRequest");
|
||||
// For a ping, we perform the reply handling here directly
|
||||
if sim_request.request == SimRequest::SimCtrl(SimCtrlRequest::Ping) {
|
||||
no_data_received = false;
|
||||
self.last_sender = Some(from);
|
||||
let sim_reply = SimReply::from(SimCtrlReply::Pong);
|
||||
let sim_reply_json = serde_json::to_string(&sim_reply)
|
||||
let sim_reply_raw = postcard::to_allocvec(&sim_reply)
|
||||
.expect("failed to serialize SimReply");
|
||||
self.udp_server
|
||||
.send_to(sim_reply_json.as_bytes(), from)
|
||||
.send_to(&sim_reply_raw, from)
|
||||
.expect("failed to send reply to client from UDP server");
|
||||
}
|
||||
// Forward each SIM request for testing purposes.
|
||||
|
||||
@@ -181,8 +181,8 @@ fn main() {
|
||||
let (mgm_0_spi_interface, mgm_1_spi_interface) = if let Some(sim_client) =
|
||||
opt_sim_client.as_mut()
|
||||
{
|
||||
sim_client.add_reply_recipient(satrs_minisim::ComponentId::Mgm0Lis3Mdl, mgm_0_sim_reply_tx);
|
||||
sim_client.add_reply_recipient(satrs_minisim::ComponentId::Mgm1Lis3Mdl, mgm_1_sim_reply_tx);
|
||||
sim_client.add_reply_recipient(minisim_types::ComponentId::Mgm0Lis3Mdl, mgm_0_sim_reply_tx);
|
||||
sim_client.add_reply_recipient(minisim_types::ComponentId::Mgm1Lis3Mdl, mgm_1_sim_reply_tx);
|
||||
(
|
||||
mgm::SpiCommunication::Sim(mgm::SpiSimInterface {
|
||||
id: mgm::MgmId::_0,
|
||||
@@ -258,7 +258,7 @@ fn main() {
|
||||
});
|
||||
|
||||
let mgt_com = if let Some(sim_client) = opt_sim_client.as_mut() {
|
||||
sim_client.add_reply_recipient(satrs_minisim::ComponentId::Mgt, mgt_sim_reply_tx);
|
||||
sim_client.add_reply_recipient(minisim_types::ComponentId::Mgt, mgt_sim_reply_tx);
|
||||
mgt::MgtCommunication::Sim(mgt::SimInterface {
|
||||
sim_request_tx: sim_request_tx.clone(),
|
||||
sim_reply_rx: mgt_sim_reply_rx,
|
||||
@@ -299,7 +299,7 @@ fn main() {
|
||||
);
|
||||
|
||||
let pcdu_serial_interface = if let Some(sim_client) = opt_sim_client.as_mut() {
|
||||
sim_client.add_reply_recipient(satrs_minisim::ComponentId::Pcdu, pcdu_sim_reply_tx);
|
||||
sim_client.add_reply_recipient(minisim_types::ComponentId::Pcdu, pcdu_sim_reply_tx);
|
||||
SerialSimInterfaceWrapper::Sim(SerialInterfaceToSim::new(
|
||||
sim_request_tx.clone(),
|
||||
pcdu_sim_reply_rx,
|
||||
|
||||
@@ -13,4 +13,4 @@ postcard = { version = "1", features = ["alloc"] }
|
||||
thiserror = { version = "2", default-features = false }
|
||||
bitbybit = "2"
|
||||
arbitrary-int = "2"
|
||||
hashbrown = { version = "0.17", features = ["serde"] }
|
||||
heapless = { version = "0.9", features = ["serde"] }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use strum::IntoEnumIterator as _;
|
||||
|
||||
#[bitbybit::bitfield(u16, debug, default = 0x0)]
|
||||
@@ -76,7 +74,10 @@ impl crate::EventId for Event {
|
||||
}
|
||||
}
|
||||
|
||||
pub type SwitchMapBinary = HashMap<SwitchId, SwitchStateBinary>;
|
||||
pub const MAX_NUM_OF_SWITCHES: usize = 16;
|
||||
|
||||
pub type SwitchMapBinary =
|
||||
heapless::index_map::FnvIndexMap<SwitchId, SwitchStateBinary, MAX_NUM_OF_SWITCHES>;
|
||||
|
||||
pub struct SwitchMapBinaryWrapper(pub SwitchMapBinary);
|
||||
|
||||
@@ -84,7 +85,9 @@ impl Default for SwitchMapBinaryWrapper {
|
||||
fn default() -> Self {
|
||||
let mut switch_map = SwitchMapBinary::default();
|
||||
for entry in SwitchId::iter() {
|
||||
switch_map.insert(entry, SwitchStateBinary::Off);
|
||||
switch_map
|
||||
.insert(entry, SwitchStateBinary::Off)
|
||||
.expect("switch map capacity exceeded");
|
||||
}
|
||||
Self(switch_map)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user