tests working again

This commit is contained in:
Robin Mueller
2026-01-16 14:11:23 +01:00
parent bcbac6e886
commit 442c31889d
7 changed files with 137 additions and 68 deletions
+1
View File
@@ -6,6 +6,7 @@ use spacepackets::{
pub mod ccsds;
pub mod control;
pub mod mgm;
pub mod pcdu;
#[derive(
+23
View File
@@ -0,0 +1,23 @@
pub mod request {
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
pub enum Request {
Ping,
}
}
pub mod response {
use crate::Message;
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
pub enum Response {
Ok,
}
impl Message for Response {
fn message_type(&self) -> crate::MessageType {
match self {
Response::Ok => crate::MessageType::Verification,
}
}
}
}
+67 -45
View File
@@ -1,9 +1,9 @@
use models::ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned};
use models::pcdu::SwitchId;
use models::ComponentId;
use models::{mgm, ComponentId};
use satrs::hk::{HkRequest, HkRequestVariant};
use satrs::mode_tree::{ModeChild, ModeNode};
use satrs::power::{PowerSwitchInfo, PowerSwitcherCommandSender};
use satrs::spacepackets::CcsdsPacketIdAndPsc;
use satrs_example::{DeviceMode, TimestampHelper};
use satrs_minisim::acs::lis3mdl::{
MgmLis3MdlReply, MgmLis3RawValues, FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR,
@@ -22,6 +22,7 @@ use satrs::mode::{
use satrs::request::{GenericMessage, MessageMetadata};
use satrs_example::config::components::NO_SENDER;
use crate::ccsds::pack_ccsds_tm_packet_for_now;
use crate::eps::PowerSwitchHelper;
use crate::spi::SpiInterface;
@@ -167,6 +168,7 @@ pub struct MgmHandlerLis3Mdl<ComInterface: SpiInterface> {
}
impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
#[allow(clippy::too_many_arguments)]
pub fn new(
id: ComponentId,
dev_str: &'static str,
@@ -194,7 +196,7 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
pub fn periodic_operation(&mut self) {
self.stamp_helper.update_from_now();
// Handle requests.
self.handle_tc();
self.handle_telecommands();
self.handle_mode_requests();
if let Some(target_mode_submode) = self.mode_helpers.target {
self.handle_mode_transition(target_mode_submode);
@@ -205,32 +207,53 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
}
}
pub fn handle_tc(&mut self) {
pub fn handle_telecommands(&mut self) {
loop {
//match self.tc_rx.try_recv() {
/*
Ok(ref msg) => match &msg.message {
CompositeRequest::Hk(hk_request) => {
self.handle_hk_request(&msg.requestor_info, hk_request)
match self.tc_rx.try_recv() {
Ok(packet) => {
let tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&packet.sp_header);
match postcard::from_bytes::<mgm::request::Request>(&packet.payload) {
Ok(request) => {
log::info!(
"received request {:?} with TC ID {:#010x}",
request,
tc_id.raw()
);
match request {
mgm::request::Request::Ping => {
self.send_telemetry(Some(tc_id), mgm::response::Response::Ok)
}
}
}
Err(e) => {
log::warn!("failed to deserialize request: {}", e);
}
}
}
// TODO: This object does not have actions (yet).. Still send back completion failure
// reply.
CompositeRequest::Action(_action_req) => {}
},
Err(e) => match e {
std::sync::mpsc::TryRecvError::Empty => break,
std::sync::mpsc::TryRecvError::Disconnected => {
log::warn!("packet sender disconnected")
}
},
}
}
}
Err(e) => {
if e != mpsc::TryRecvError::Empty {
log::warn!(
"{}: failed to receive composite request: {:?}",
self.dev_str,
e
);
} else {
break;
pub fn send_telemetry(
&self,
tc_id: Option<CcsdsPacketIdAndPsc>,
response: mgm::response::Response,
) {
match pack_ccsds_tm_packet_for_now(self.id, tc_id, &response) {
Ok(packet) => {
if let Err(e) = self.tm_tx.send(packet) {
log::warn!("failed to send TM packet: {}", e);
}
}
*/
//}
Err(e) => {
log::warn!("failed to pack TM packet: {}", e);
}
}
}
@@ -477,7 +500,7 @@ mod tests {
};
use models::{
pcdu::{SwitchRequest, SwitchStateBinary},
pcdu::{SwitchRequest, SwitchState, SwitchStateBinary},
ComponentId,
};
use satrs::{
@@ -488,7 +511,7 @@ mod tests {
};
use satrs_minisim::acs::lis3mdl::MgmLis3RawValues;
use crate::eps::{pcdu::SharedSwitchSet, TestSwitchHelper};
use crate::eps::pcdu::{SharedSwitchSet, SwitchMap, SwitchSet};
use super::*;
@@ -516,7 +539,7 @@ mod tests {
#[allow(dead_code)]
pub struct MgmTestbench {
pub mode_request_tx: mpsc::SyncSender<GenericMessage<ModeRequest>>,
pub mode_reply_rx_to_pus: mpsc::Receiver<GenericMessage<ModeReply>>,
pub mode_reply_rx_to_ground: mpsc::Receiver<GenericMessage<ModeReply>>,
pub mode_reply_rx_to_parent: mpsc::Receiver<GenericMessage<ModeReply>>,
pub shared_switch_set: SharedSwitchSet,
pub tc_tx: mpsc::SyncSender<CcsdsTcPacketOwned>,
@@ -576,7 +599,10 @@ mod tests {
let (_tm_tx, tm_rx) = mpsc::sync_channel(10);
let (switcher_tx, switch_rx) = mpsc::sync_channel(10);
let shared_mgm_set = Arc::default();
let shared_switch_set = SharedSwitchSet::default();
let mut switch_map = SwitchMap::new();
switch_map.insert(SwitchId::Mgm0, SwitchState::Off);
let switch_map = SwitchSet::new(switch_map);
let shared_switch_set = SharedSwitchSet::new(Mutex::new(switch_map));
let mut handler = MgmHandlerLis3Mdl::new(
ComponentId::AcsMgm0,
"TEST_MGM",
@@ -591,7 +617,7 @@ mod tests {
handler.add_mode_parent(ComponentId::AcsMgmAssembly as u32, reply_tx_to_parent);
Self {
mode_request_tx: request_tx,
mode_reply_rx_to_pus: reply_rx_to_ground,
mode_reply_rx_to_ground: reply_rx_to_ground,
mode_reply_rx_to_parent: reply_rx_to_parent,
shared_switch_set,
switch_rx,
@@ -642,26 +668,22 @@ mod tests {
assert_eq!(testbench.handler.mode_and_submode().submode(), 0);
// Verify power switch handling.
/*
let mut switch_requests = testbench.handler.switch_helper.switch_requests.borrow_mut();
assert_eq!(switch_requests.len(), 1);
let switch_req = switch_requests.pop_front().expect("no switch request");
assert_eq!(switch_req.target_state, SwitchStateBinary::On);
assert_eq!(switch_req.switch_id, SwitchId::Mgm0);
let mut switch_info_requests = testbench
.handler
.switch_helper
.switch_info_requests
.borrow_mut();
assert_eq!(switch_info_requests.len(), 1);
let switch_info_req = switch_info_requests.pop_front().expect("no switch request");
*/
let switch_req = testbench.switch_rx.try_recv().expect("no switch request");
assert_eq!(switch_req.message.switch_id, SwitchId::Mgm0);
assert_eq!(switch_req.message.target_state, SwitchStateBinary::On);
// This simulates one cycle for the power switch to update.
testbench
.shared_switch_set
.lock()
.unwrap()
.set_switch_state(SwitchId::Mgm0, SwitchState::On);
// Now the power switch is updated and the mode request should be completed.
testbench.handler.periodic_operation();
let mode_reply = testbench
.mode_reply_rx_to_pus
.mode_reply_rx_to_ground
.try_recv()
.expect("no mode reply generated");
match mode_reply.message {
@@ -672,7 +694,7 @@ mod tests {
_ => panic!("unexpected mode reply"),
}
// The device should have been polled once.
assert_eq!(testbench.handler.com_interface.call_count, 1);
assert_eq!(testbench.handler.com_interface.call_count, 2);
let mgm_set = *testbench.handler.shared_mgm_set.lock().unwrap();
assert!(mgm_set.x < 0.001);
assert!(mgm_set.y < 0.001);
+7 -4
View File
@@ -20,6 +20,10 @@ impl Controller {
}
pub fn periodic_operation(&mut self) {
self.handle_telecommands();
}
pub fn handle_telecommands(&mut self) {
loop {
match self.tc_rx.try_recv() {
Ok(packet) => {
@@ -32,9 +36,8 @@ impl Controller {
tc_id.raw()
);
match request {
control::request::Request::Ping => {
self.send_tm(Some(tc_id), control::response::Response::Ok)
}
control::request::Request::Ping => self
.send_telemetry(Some(tc_id), control::response::Response::Ok),
}
}
Err(e) => {
@@ -52,7 +55,7 @@ impl Controller {
}
}
pub fn send_tm(
pub fn send_telemetry(
&self,
tc_id: Option<CcsdsPacketIdAndPsc>,
response: control::response::Response,
+36 -16
View File
@@ -31,12 +31,34 @@ use strum::IntoEnumIterator as _;
use crate::ccsds::pack_ccsds_tm_packet_for_now;
#[derive(Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SwitchSet {
pub valid: bool,
pub switch_map: SwitchMap,
}
impl SwitchSet {
pub fn new(switch_map: SwitchMap) -> Self {
Self {
valid: true,
switch_map,
}
}
pub fn new_with_init_switches_unknown() -> Self {
let wrapper = SwitchMapWrapper::default();
Self::new(wrapper.0)
}
pub fn set_switch_state(&mut self, switch_id: SwitchId, state: SwitchState) -> bool {
if !self.switch_map.contains_key(&switch_id) {
return false;
}
*self.switch_map.get_mut(&switch_id).unwrap() = state;
true
}
}
pub type SwitchMap = HashMap<SwitchId, SwitchState>;
pub struct SwitchMapWrapper(pub SwitchMap);
@@ -375,19 +397,16 @@ impl<ComInterface: SerialInterface> PcduHandler<ComInterface> {
pub fn handle_switch_requests(&mut self) {
loop {
match self.switch_request_rx.try_recv() {
Ok(switch_req) => match SwitchId::try_from(switch_req.message.switch_id()) {
Ok(pcdu_switch) => {
let pcdu_req = PcduRequest::SwitchDevice {
switch: pcdu_switch,
state: switch_req.message.target_state(),
};
let pcdu_req_ser = serde_json::to_string(&pcdu_req).unwrap();
self.com_interface
.send(pcdu_req_ser.as_bytes())
.expect("failed to send switch request to PCDU");
}
Err(e) => todo!("failed to convert switch ID {:?} to typed PCDU switch", e),
},
Ok(switch_req) => {
let pcdu_req = PcduRequest::SwitchDevice {
switch: switch_req.message.switch_id(),
state: switch_req.message.target_state(),
};
let pcdu_req_ser = serde_json::to_string(&pcdu_req).unwrap();
self.com_interface
.send(pcdu_req_ser.as_bytes())
.expect("failed to send switch request to PCDU");
}
Err(e) => match e {
mpsc::TryRecvError::Empty => break,
mpsc::TryRecvError::Disconnected => {
@@ -581,7 +600,8 @@ mod tests {
let (tc_tx, tc_rx) = mpsc::sync_channel(5);
let (tm_tx, tm_rx) = mpsc::sync_channel(5);
let (switch_request_tx, switch_reqest_rx) = mpsc::channel();
let shared_switch_map = Arc::new(Mutex::new(SwitchSet::default()));
let shared_switch_map =
Arc::new(Mutex::new(SwitchSet::new_with_init_switches_unknown()));
let mut handler = PcduHandler::new(
mode_node,
tc_rx,
@@ -693,7 +713,7 @@ mod tests {
))
.expect("failed to send mode request");
let switch_map_shared = testbench.handler.shared_switch_map.lock().unwrap();
assert!(!switch_map_shared.valid);
assert!(switch_map_shared.valid);
drop(switch_map_shared);
testbench.handler.periodic_operation(OpCode::RegularOp);
testbench
+2 -2
View File
@@ -38,6 +38,7 @@ use tmtc::{tc_source::TcSourceTask, tm_sink::TmSink};
use crate::{
acs::mgm::{MgmHandlerLis3Mdl, SpiDummyInterface, SpiSimInterface, SpiSimInterfaceWrapper},
control::Controller,
eps::pcdu::SwitchSet,
interface::udp::UdpTmHandlerWithChannel,
tmtc::tc_source::CcsdsDistributor,
};
@@ -46,7 +47,6 @@ mod acs;
mod ccsds;
mod control;
mod eps;
//mod hk;
mod interface;
mod logger;
mod spi;
@@ -125,7 +125,7 @@ fn main() {
let mut tm_sink = TmSink::new(sync_tm_tcp_source, tm_sink_rx, tm_server_tx);
let shared_switch_set = Arc::new(Mutex::default());
let shared_switch_set = Arc::new(Mutex::new(SwitchSet::new_with_init_switches_unknown()));
let (switch_request_tx, switch_request_rx) = mpsc::sync_channel(20);
let switch_helper = PowerSwitchHelper::new(switch_request_tx, shared_switch_set.clone());
+1 -1
View File
@@ -162,8 +162,8 @@ impl TmSink {
let zero_copy_writer =
PusTmZeroCopyWriter::new(&mut tm_raw, MIN_CDS_FIELD_LEN, true)
.expect("Creating TM zero copy writer failed");
self.common.apply_packet_processing(zero_copy_writer);
*/
//self.common.apply_packet_processing(zero_copy_writer);
self.common.sync_tm_tcp_source.add_tm(&tm.to_vec());
self.tm_server_tx
.send(tm)