diff --git a/Cargo.toml b/Cargo.toml index 2283da4..ca32218 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "examples/types", "examples/client", "examples/minisim", + "examples/minisim-types", "satrs-shared", "tmtc-utils", "examples/embedded-client", diff --git a/examples/client/Cargo.toml b/examples/client/Cargo.toml index 6ba5aa1..6fc4f73 100644 --- a/examples/client/Cargo.toml +++ b/examples/client/Cargo.toml @@ -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" diff --git a/examples/client/src/main.rs b/examples/client/src/main.rs index 5a08238..9a0bf5f 100644 --- a/examples/client/src/main.rs +++ b/examples/client/src/main.rs @@ -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(()) } diff --git a/examples/minisim-types/Cargo.toml b/examples/minisim-types/Cargo.toml new file mode 100644 index 0000000..e639936 --- /dev/null +++ b/examples/minisim-types/Cargo.toml @@ -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"] } diff --git a/examples/minisim/src/lib.rs b/examples/minisim-types/src/lib.rs similarity index 80% rename from examples/minisim/src/lib.rs rename to examples/minisim-types/src/lib.rs index 6007b68..1b2d021 100644 --- a/examples/minisim/src/lib.rs +++ b/examples/minisim-types/src/lib.rs @@ -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); } } diff --git a/examples/minisim/Cargo.toml b/examples/minisim/Cargo.toml index c654647..bccf160 100644 --- a/examples/minisim/Cargo.toml +++ b/examples/minisim/Cargo.toml @@ -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" diff --git a/examples/minisim/src/acs/mgm.rs b/examples/minisim/src/acs/mgm.rs index e0573b1..a3b2b58 100644 --- a/examples/minisim/src/acs/mgm.rs +++ b/examples/minisim/src/acs/mgm.rs @@ -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) { 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::{ diff --git a/examples/minisim/src/acs/mgt.rs b/examples/minisim/src/acs/mgt.rs index d9e98e7..35a28a7 100644 --- a/examples/minisim/src/acs/mgt.rs +++ b/examples/minisim/src/acs/mgt.rs @@ -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, diff --git a/examples/minisim/src/controller.rs b/examples/minisim/src/controller.rs index 8346680..d0c91bf 100644 --- a/examples/minisim/src/controller.rs +++ b/examples/minisim/src/controller.rs @@ -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::{ diff --git a/examples/minisim/src/eps.rs b/examples/minisim/src/eps.rs index e07b7da..8b0d05c 100644 --- a/examples/minisim/src/eps.rs +++ b/examples/minisim/src/eps.rs @@ -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; diff --git a/examples/minisim/src/main.rs b/examples/minisim/src/main.rs index 171fd9c..d605b1e 100644 --- a/examples/minisim/src/main.rs +++ b/examples/minisim/src/main.rs @@ -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; diff --git a/examples/minisim/src/test_helpers.rs b/examples/minisim/src/test_helpers.rs index ca579df..3bbed32 100644 --- a/examples/minisim/src/test_helpers.rs +++ b/examples/minisim/src/test_helpers.rs @@ -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}; diff --git a/examples/minisim/src/udp.rs b/examples/minisim/src/udp.rs index 73f3aa1..d014c64 100644 --- a/examples/minisim/src/udp.rs +++ b/examples/minisim/src/udp.rs @@ -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::(&self.req_buf[..bytes_read]); + let sim_req = postcard::from_bytes::(&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 { 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 { 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}"); } }, } diff --git a/examples/obsw-std/Cargo.toml b/examples/obsw-std/Cargo.toml index d43ab3c..e15d93c 100644 --- a/examples/obsw-std/Cargo.toml +++ b/examples/obsw-std/Cargo.toml @@ -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] diff --git a/examples/obsw-std/src/acs/mgm.rs b/examples/obsw-std/src/acs/mgm.rs index 913a0ad..09b7257 100644 --- a/examples/obsw-std/src/acs/mgm.rs +++ b/examples/obsw-std/src/acs/mgm.rs @@ -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, diff --git a/examples/obsw-std/src/acs/mgt.rs b/examples/obsw-std/src/acs/mgt.rs index 2044ef4..73c7fad 100644 --- a/examples/obsw-std/src/acs/mgt.rs +++ b/examples/obsw-std/src/acs/mgt.rs @@ -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}, diff --git a/examples/obsw-std/src/eps/pcdu.rs b/examples/obsw-std/src/eps/pcdu.rs index df30b34..b50ba1a 100644 --- a/examples/obsw-std/src/eps/pcdu.rs +++ b/examples/obsw-std/src/eps/pcdu.rs @@ -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 { 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 PcduHandler { 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 PcduHandler { 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 PcduHandler { 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>>, - pub reply_queue: RefCell>, + pub reply_queue: RefCell>>, /// Makes the next `send` call fail, to exercise comm-error handling. pub fail_next_send: RefCell, } @@ -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)) diff --git a/examples/obsw-std/src/interface/sim_client_udp.rs b/examples/obsw-std/src/interface/sim_client_udp.rs index 83c90e4..dce8b07 100644 --- a/examples/obsw-std/src/interface/sim_client_udp.rs +++ b/examples/obsw-std/src/interface/sim_client_udp.rs @@ -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>); @@ -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), } 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 = - serde_json::from_slice(&self.reply_buf[0..recvd_bytes]); + let sim_reply_result: postcard::Result = + 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. diff --git a/examples/obsw-std/src/main.rs b/examples/obsw-std/src/main.rs index b00ba09..fdbb824 100644 --- a/examples/obsw-std/src/main.rs +++ b/examples/obsw-std/src/main.rs @@ -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, diff --git a/examples/types/Cargo.toml b/examples/types/Cargo.toml index 23535b6..5b95927 100644 --- a/examples/types/Cargo.toml +++ b/examples/types/Cargo.toml @@ -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"] } diff --git a/examples/types/src/pcdu.rs b/examples/types/src/pcdu.rs index 2299403..1c9e821 100644 --- a/examples/types/src/pcdu.rs +++ b/examples/types/src/pcdu.rs @@ -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; +pub const MAX_NUM_OF_SWITCHES: usize = 16; + +pub type SwitchMapBinary = + heapless::index_map::FnvIndexMap; 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) }