use edition 2024, continue re-work

This commit is contained in:
Robin Mueller
2026-03-12 17:54:33 +01:00
parent 2de2898ba4
commit 70f43fd9e5
17 changed files with 311 additions and 149 deletions
+65 -57
View File
@@ -1,14 +1,13 @@
use models::ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned};
use models::mgm::response::ModeFailure;
use models::mgm::MgmData;
use models::mgm::response::ModeFailure;
use models::pcdu::SwitchId;
use models::{mgm, ComponentId, DeviceMode, HkRequestType};
use models::{ComponentId, DeviceMode, HkRequestType, mgm};
use satrs::spacepackets::CcsdsPacketIdAndPsc;
use satrs_example::{HkHelperSingleSet, ModeHelper, TimestampHelper, TransitionState};
use satrs_minisim::acs::lis3mdl::{
MgmLis3MdlReply, MgmLis3RawValues, FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR,
};
use satrs_example::{HkHelperSingleSet, ModeHelper, TimestampHelper, TmtcQueues};
use satrs_minisim::acs::MgmRequestLis3Mdl;
use satrs_minisim::acs::lis3mdl::{
FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR, MgmLis3MdlReply, MgmLis3RawValues,
};
use satrs_minisim::{SerializableSimMsgPayload, SimReply, SimRequest};
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
@@ -49,12 +48,21 @@ impl MgmId {
}
}
#[derive(Default, Debug, PartialEq, Eq)]
pub enum TransitionState {
#[default]
Idle,
PowerSwitching,
Done,
}
pub enum ModeRequest {
SetMode(DeviceMode),
ReadMode,
}
pub enum ModeReport {
/// New mode has been set.
Mode(DeviceMode),
/// Setting a mode timed out.
SetModeTimeout,
@@ -73,6 +81,21 @@ impl SpiDummyInterface {
}
}
#[derive(Default)]
pub struct TestSpiInterface {
pub call_count: u32,
pub next_mgm_data: MgmLis3RawValues,
}
impl TestSpiInterface {
fn transfer(&mut self, _tx: &[u8], rx: &mut [u8]) {
rx[X_LOWBYTE_IDX..X_LOWBYTE_IDX + 2].copy_from_slice(&self.next_mgm_data.x.to_le_bytes());
rx[Y_LOWBYTE_IDX..Y_LOWBYTE_IDX + 2].copy_from_slice(&self.next_mgm_data.y.to_le_bytes());
rx[Z_LOWBYTE_IDX..Z_LOWBYTE_IDX + 2].copy_from_slice(&self.next_mgm_data.z.to_le_bytes());
self.call_count += 1;
}
}
pub struct SpiSimInterface {
pub sim_request_tx: mpsc::Sender<SimRequest>,
pub sim_reply_rx: mpsc::Receiver<SimReply>,
@@ -109,6 +132,8 @@ impl SpiSimInterface {
pub enum SpiCommunication {
Dummy(SpiDummyInterface),
Sim(SpiSimInterface),
#[allow(dead_code)]
Test(TestSpiInterface),
}
impl SpiCommunication {
@@ -116,6 +141,7 @@ impl SpiCommunication {
match self {
SpiCommunication::Dummy(dummy) => dummy.transfer(tx, rx),
SpiCommunication::Sim(sim_if) => sim_if.transfer(tx, rx),
SpiCommunication::Test(test_if) => test_if.transfer(tx, rx),
}
}
}
@@ -135,34 +161,31 @@ pub struct ModeLeafHelper {
/// Example MGM device handler strongly based on the LIS3MDL MEMS device.
pub struct MgmHandlerLis3Mdl {
id: MgmId,
tc_rx: mpsc::Receiver<CcsdsTcPacketOwned>,
tm_tx: mpsc::SyncSender<CcsdsTmPacketOwned>,
switch_helper: PowerSwitchHelper,
pub com_interface: SpiCommunication,
tmtc_queues: TmtcQueues,
pub spi_com: SpiCommunication,
shared_mgm_set: Arc<Mutex<MgmData>>,
buffers: BufWrapper,
stamp_helper: TimestampHelper,
hk_helper: HkHelperSingleSet,
mode_helpers: ModeHelper<DeviceMode>,
mode_helpers: ModeHelper<DeviceMode, TransitionState>,
mode_leaf_helper: ModeLeafHelper,
}
impl MgmHandlerLis3Mdl {
pub fn new(
id: MgmId,
tc_rx: mpsc::Receiver<CcsdsTcPacketOwned>,
tm_tx: mpsc::SyncSender<CcsdsTmPacketOwned>,
tmtc_queues: TmtcQueues,
switch_helper: PowerSwitchHelper,
com_interface: SpiCommunication,
spi_com: SpiCommunication,
shared_mgm_set: Arc<Mutex<MgmData>>,
mode_leaf_helper: ModeLeafHelper,
) -> Self {
Self {
id,
tc_rx,
tm_tx,
tmtc_queues,
switch_helper,
com_interface,
spi_com,
shared_mgm_set,
mode_helpers: ModeHelper::new(DeviceMode::Off, Duration::from_millis(200)),
buffers: BufWrapper::default(),
@@ -182,7 +205,6 @@ impl MgmHandlerLis3Mdl {
match self.id {
MgmId::_0 => SwitchId::Mgm0,
MgmId::_1 => SwitchId::Mgm1,
_ => panic!("unexpected component id"),
}
}
@@ -213,7 +235,7 @@ impl MgmHandlerLis3Mdl {
pub fn handle_telecommands(&mut self) {
loop {
match self.tc_rx.try_recv() {
match self.tmtc_queues.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) {
@@ -275,7 +297,7 @@ impl MgmHandlerLis3Mdl {
) {
match pack_ccsds_tm_packet_for_now(self.id.component_id(), tc_id, &response) {
Ok(packet) => {
if let Err(e) = self.tm_tx.send(packet) {
if let Err(e) = self.tmtc_queues.tm_tx.send(packet) {
log::warn!("failed to send TM packet: {}", e);
}
}
@@ -319,12 +341,10 @@ impl MgmHandlerLis3Mdl {
pub fn poll_sensor(&mut self) {
// Communicate with the device. This is actually how to read the data from the LIS3 device
// SPI interface.
self.com_interface
.transfer(
&self.buffers.tx_buf[0..NR_OF_DATA_AND_CFG_REGISTERS + 1],
&mut self.buffers.rx_buf[0..NR_OF_DATA_AND_CFG_REGISTERS + 1],
)
.expect("failed to transfer data");
self.spi_com.transfer(
&self.buffers.tx_buf[0..NR_OF_DATA_AND_CFG_REGISTERS + 1],
&mut self.buffers.rx_buf[0..NR_OF_DATA_AND_CFG_REGISTERS + 1],
);
let x_raw = i16::from_le_bytes(
self.buffers.rx_buf[X_LOWBYTE_IDX..X_LOWBYTE_IDX + 2]
.try_into()
@@ -429,15 +449,16 @@ impl MgmHandlerLis3Mdl {
#[cfg(test)]
mod tests {
use std::sync::{
mpsc::{self, TryRecvError},
Arc,
mpsc::{self, TryRecvError},
};
use arbitrary_int::u11;
use models::{
Apid, ComponentId, TcHeader,
ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned},
mgm::request::HkRequest,
pcdu::{SwitchRequest, SwitchState, SwitchStateBinary},
Apid, ComponentId, TcHeader,
};
use satrs::{request::GenericMessage, spacepackets::SpacePacketHeader};
use satrs_minisim::acs::lis3mdl::MgmLis3RawValues;
@@ -472,27 +493,6 @@ mod tests {
)
}
#[derive(Default)]
pub struct TestSpiInterface {
pub call_count: u32,
pub next_mgm_data: MgmLis3RawValues,
}
impl SpiCommunication for TestSpiInterface {
type Error = ();
fn transfer(&mut self, _tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
rx[X_LOWBYTE_IDX..X_LOWBYTE_IDX + 2]
.copy_from_slice(&self.next_mgm_data.x.to_le_bytes());
rx[Y_LOWBYTE_IDX..Y_LOWBYTE_IDX + 2]
.copy_from_slice(&self.next_mgm_data.y.to_le_bytes());
rx[Z_LOWBYTE_IDX..Z_LOWBYTE_IDX + 2]
.copy_from_slice(&self.next_mgm_data.z.to_le_bytes());
self.call_count += 1;
Ok(())
}
}
#[allow(dead_code)]
pub struct MgmTestbench {
pub assembly_mode_request_tx: mpsc::SyncSender<ModeRequest>,
@@ -501,7 +501,7 @@ mod tests {
pub tc_tx: mpsc::SyncSender<CcsdsTcPacketOwned>,
pub tm_rx: mpsc::Receiver<CcsdsTmPacketOwned>,
pub switch_rx: mpsc::Receiver<GenericMessage<SwitchRequest>>,
pub handler: MgmHandlerLis3Mdl<TestSpiInterface>,
pub handler: MgmHandlerLis3Mdl,
}
impl MgmTestbench {
@@ -522,10 +522,9 @@ mod tests {
let shared_switch_set = SharedSwitchSet::new(Mutex::new(switch_map));
let handler = MgmHandlerLis3Mdl::new(
MgmId::_0,
tc_rx,
tm_tx,
TmtcQueues { tc_rx, tm_tx },
PowerSwitchHelper::new(switcher_tx, shared_switch_set.clone()),
TestSpiInterface::default(),
SpiCommunication::Test(TestSpiInterface::default()),
shared_mgm_set,
mode_leaf_helper,
);
@@ -539,16 +538,25 @@ mod tests {
tc_tx,
}
}
pub fn test_spi_interface(&mut self) -> &mut TestSpiInterface {
match &mut self.handler.spi_com {
SpiCommunication::Dummy(_) | SpiCommunication::Sim(_) => {
panic!("unexpected SPI interface")
}
SpiCommunication::Test(test_spi_interface) => test_spi_interface,
}
}
}
#[test]
fn test_basic_handler() {
let mut testbench = MgmTestbench::new();
assert_eq!(testbench.handler.com_interface.call_count, 0);
assert_eq!(testbench.test_spi_interface().call_count, 0);
assert_eq!(testbench.handler.mode(), DeviceMode::Off);
testbench.handler.periodic_operation();
// Handler is OFF, no changes expected.
assert_eq!(testbench.handler.com_interface.call_count, 0);
assert_eq!(testbench.test_spi_interface().call_count, 0);
assert_eq!(testbench.handler.mode(), DeviceMode::Off);
}
@@ -590,7 +598,7 @@ mod tests {
.expect("failed to deserialize mode reply");
matches!(response, models::mgm::response::Response::Ok);
// The device should have been polled once.
assert_eq!(testbench.handler.com_interface.call_count, 1);
assert_eq!(testbench.test_spi_interface().call_count, 1);
let mgm_set = *testbench.handler.shared_mgm_set.lock().unwrap();
assert!(mgm_set.x < 0.001);
assert!(mgm_set.y < 0.001);
@@ -608,7 +616,7 @@ mod tests {
y: -1000,
z: 1000,
};
testbench.handler.com_interface.next_mgm_data = raw_values;
testbench.test_spi_interface().next_mgm_data = raw_values;
testbench
.tc_tx
.send(create_request_tc(
+138 -14
View File
@@ -5,19 +5,20 @@
use std::{sync::mpsc, time::Duration};
use models::DeviceMode;
use satrs_example::ModeHelper;
use satrs_example::{ModeHelper, TmtcQueues};
pub enum ModeRequest {
SetMode(DeviceMode),
SetMode(AssemblyMode),
ReadMode,
}
pub enum ModeReport {
Mode(DeviceMode),
/// Setting a mode timed out.
SetModeTimeout,
/// An assembly child lost the mode.
ChildLostMode,
/// Mode of the assembly.
Mode(AssemblyMode),
/// Failure setting the children mode.
SetModeRetryLimitReached([DeviceMode; 2]),
/// An assembly can not keep its mode.
CanNotKeepMode([DeviceMode; 2]),
}
pub struct ParentQueueHelper {
@@ -31,34 +32,157 @@ pub struct ChildrenQueueHelper {
pub report_rx_queues: [mpsc::Receiver<super::mgm::ModeReport>; 2],
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum TransitionState {
#[default]
Idle,
CommandingChildren {
step: usize,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AssemblyMode {
/// The assembly mode ressembles the modes of the devices it controls. It also tries to keep
/// the children in the correct mode by re-commanding them into the correct mode.
Device(DeviceMode),
/// Mode keeping disabled.
NoModeKeeping,
}
/// MGM assembly component.
pub struct Assembly {
mode_helper: ModeHelper<DeviceMode>,
mode_helper: ModeHelper<AssemblyMode, TransitionState>,
/// This boolean is used for the distinction between transitions commanded by the parent
/// or by ground, and transitions which were commanded autonomously as part of children
/// mode keeping.
mode_keeping_transition: bool,
tmtc_queues: TmtcQueues,
mgm_modes: [DeviceMode; 2],
parent_queues: ParentQueueHelper,
pub(crate) children_queues: ChildrenQueueHelper,
}
impl Assembly {
pub fn new(parent_queues: ParentQueueHelper, children_queues: ChildrenQueueHelper) -> Self {
const RETRIES: usize = 3;
pub fn new(
parent_queues: ParentQueueHelper,
children_queues: ChildrenQueueHelper,
tmtc_queues: TmtcQueues,
) -> Self {
Self {
mode_helper: ModeHelper::new(DeviceMode::Unknown, Duration::from_millis(200)),
mode_helper: ModeHelper::new(AssemblyMode::NoModeKeeping, Duration::from_millis(200)),
mode_keeping_transition: false,
tmtc_queues,
mgm_modes: [DeviceMode::Off; 2],
parent_queues,
children_queues,
}
}
pub fn periodic_operation(&mut self) {
self.handle_parent_mode_queue();
self.handle_children_mode_queues();
if self.mode_helper.transition_active() {
self.handle_mode_transition();
}
}
pub fn handle_mode_transition(&mut self) {
if self.mode_helper.transition_state == TransitionState::Idle {
self.mode_helper.transition_state = TransitionState::CommandingChildren { step: 0 };
}
if let TransitionState::CommandingChildren { step } = self.mode_helper.transition_state
&& self.mode_helper.timed_out()
{
if step >= Self::RETRIES {
let report = if self.mode_keeping_transition {
ModeReport::CanNotKeepMode(self.mgm_modes)
} else {
ModeReport::SetModeRetryLimitReached(self.mgm_modes)
};
self.parent_queues.report_tx.send(report).unwrap();
self.mode_helper.finish(false);
}
if let AssemblyMode::Device(device_mode) = self.mode_helper.target.unwrap() {
self.command_children(device_mode);
} else {
self.mode_helper.finish(true);
}
self.mode_helper.transition_state =
TransitionState::CommandingChildren { step: step + 1 }
}
}
pub fn command_children(&self, mode: DeviceMode) {
for tx in &self.children_queues.request_tx_queues {
tx.send(super::mgm::ModeRequest::SetMode(mode)).unwrap();
}
}
pub fn handle_parent_mode_queue(&mut self) {
loop {
match self.parent_queues.request_rx.try_recv() {
Ok(request) => match request {
ModeRequest::SetMode(assembly_mode) => match assembly_mode {
AssemblyMode::Device(device_mode) => {
self.mode_keeping_transition = false;
self.mode_helper.start(AssemblyMode::Device(device_mode));
}
AssemblyMode::NoModeKeeping => {
self.mode_helper.current = AssemblyMode::NoModeKeeping
}
},
ModeRequest::ReadMode => self
.parent_queues
.report_tx
.send(ModeReport::Mode(self.mode_helper.current))
.unwrap(),
},
Err(e) => match e {
mpsc::TryRecvError::Empty => break,
mpsc::TryRecvError::Disconnected => {
log::warn!("packet sender disconnected")
}
},
}
}
}
pub fn handle_children_mode_queues(&mut self) {
for rx in &mut self.children_queues.report_rx_queues {
for (idx, rx) in self.children_queues.report_rx_queues.iter_mut().enumerate() {
loop {
match rx.try_recv() {
// TODO: Do something with the report.
Ok(report) => match report {
super::mgm::ModeReport::Mode(_device_mode) => todo!(),
super::mgm::ModeReport::SetModeTimeout => todo!(),
super::mgm::ModeReport::Mode(device_mode) => {
self.mgm_modes[idx] = device_mode;
// Transition is active, check for completion.
// If at least one child reached the correct mode, we are done.
if self.mode_helper.transition_active()
&& let AssemblyMode::Device(device_mode) =
self.mode_helper.target.unwrap()
&& self.mgm_modes.contains(&device_mode)
{
self.mode_helper.finish(true);
}
// Mode keeping active: Check children modes.
if let AssemblyMode::Device(device_mode) = self.mode_helper.current
&& self.mgm_modes.iter().all(|m| *m != device_mode)
{
self.mode_keeping_transition = true;
// Children lost mode. Try to command them back to the correct
// mode.
self.mode_helper.start(self.mode_helper.current);
}
}
super::mgm::ModeReport::SetModeTimeout => {
// Ignore, handle this with our own timeout.
log::warn!("MGM {} mode timeout", idx);
}
},
Err(e) => match e {
mpsc::TryRecvError::Empty => break,
+2 -2
View File
@@ -1,8 +1,8 @@
use arbitrary_int::u11;
use models::{ccsds::CcsdsTmPacketOwned, Apid, ComponentId, Message, TmHeader};
use models::{Apid, ComponentId, Message, TmHeader, ccsds::CcsdsTmPacketOwned};
use satrs::spacepackets::{
time::{cds::CdsTime, StdTimestampError},
CcsdsPacketIdAndPsc, SpHeader,
time::{StdTimestampError, cds::CdsTime},
};
use serde::Serialize;
+2 -1
View File
@@ -1,6 +1,7 @@
use models::{
ComponentId,
ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned},
control, ComponentId,
control,
};
use satrs::spacepackets::CcsdsPacketIdAndPsc;
+4 -4
View File
@@ -1,24 +1,24 @@
use std::{
cell::RefCell,
collections::{HashMap, VecDeque},
sync::{mpsc, Arc, Mutex},
sync::{Arc, Mutex, mpsc},
};
use derive_new::new;
use models::{
ComponentId, DeviceMode,
ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned},
pcdu::{
self, SwitchId, SwitchMapBinary, SwitchMapBinaryWrapper, SwitchRequest, SwitchState,
SwitchStateBinary, SwitchesBitfield,
},
ComponentId, DeviceMode,
};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use satrs::{request::GenericMessage, spacepackets::CcsdsPacketIdAndPsc};
use satrs_example::TimestampHelper;
use satrs_minisim::{
eps::{PcduReply, PcduRequest},
SerializableSimMsgPayload, SimReply, SimRequest,
eps::{PcduReply, PcduRequest},
};
use serde::{Deserialize, Serialize};
use strum::IntoEnumIterator as _;
@@ -532,8 +532,8 @@ mod tests {
use arbitrary_int::u11;
use models::{
pcdu::{SwitchMapBinary, SwitchStateBinary},
Apid, TcHeader,
pcdu::{SwitchMapBinary, SwitchStateBinary},
};
use satrs::{
mode::{ModeReply, ModeRequest},
+1 -1
View File
@@ -1,4 +1,4 @@
use models::{ccsds::CcsdsTmPacketOwned, control, ComponentId, Event, Message};
use models::{ComponentId, Event, Message, ccsds::CcsdsTmPacketOwned, control};
use crate::ccsds::pack_ccsds_tm_packet_for_now;
@@ -7,8 +7,8 @@ use std::{
use satrs::pus::HandlingStatus;
use satrs_minisim::{
udp::SIM_CTRL_PORT, SerializableSimMsgPayload, SimComponent, SimMessageProvider, SimReply,
SimRequest,
SerializableSimMsgPayload, SimComponent, SimMessageProvider, SimReply, SimRequest,
udp::SIM_CTRL_PORT,
};
use satrs_minisim::{SimCtrlReply, SimCtrlRequest};
@@ -187,16 +187,17 @@ pub mod tests {
collections::HashMap,
net::{SocketAddr, UdpSocket},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
mpsc, Arc,
mpsc,
},
time::Duration,
};
use satrs_minisim::{
eps::{PcduReply, PcduRequest},
SerializableSimMsgPayload, SimComponent, SimCtrlReply, SimCtrlRequest, SimMessageProvider,
SimReply, SimRequest,
eps::{PcduReply, PcduRequest},
};
use super::SimClientUdp;
+5 -5
View File
@@ -1,7 +1,7 @@
#![allow(dead_code)]
use std::collections::VecDeque;
use std::net::{SocketAddr, UdpSocket};
use std::sync::{mpsc, Arc, Mutex};
use std::sync::{Arc, Mutex, mpsc};
use log::warn;
use models::ccsds::CcsdsTmPacketOwned;
@@ -115,11 +115,11 @@ mod tests {
use models::Apid;
use satrs::spacepackets::ecss::{CreatorConfig, MessageTypeId};
use satrs::{
spacepackets::{
ecss::{tc::PusTcCreator, WritablePusPacket},
SpHeader,
},
ComponentId,
spacepackets::{
SpHeader,
ecss::{WritablePusPacket, tc::PusTcCreator},
},
};
use satrs_example::config::OBSW_SERVER_ADDR;
+18 -11
View File
@@ -1,9 +1,13 @@
extern crate alloc;
use std::time::{Duration, Instant};
use std::{
sync::mpsc,
time::{Duration, Instant},
};
pub use models::ComponentId;
use satrs::spacepackets::{time::cds::CdsTime, CcsdsPacketIdAndPsc};
use models::ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned};
use satrs::spacepackets::{CcsdsPacketIdAndPsc, time::cds::CdsTime};
pub mod config;
@@ -91,16 +95,13 @@ impl HkHelperSingleSet {
}
}
#[derive(Default, Debug, PartialEq, Eq)]
pub enum TransitionState {
#[default]
Idle,
PowerSwitching,
Done,
pub struct TmtcQueues {
pub tc_rx: mpsc::Receiver<CcsdsTcPacketOwned>,
pub tm_tx: mpsc::SyncSender<CcsdsTmPacketOwned>,
}
#[derive(Debug)]
pub struct ModeHelper<Mode> {
pub struct ModeHelper<Mode, TransitionState> {
pub current: Mode,
pub target: Option<Mode>,
pub tc_id: Option<CcsdsPacketIdAndPsc>,
@@ -109,7 +110,7 @@ pub struct ModeHelper<Mode> {
pub transition_state: TransitionState,
}
impl<Mode: Copy + Clone> ModeHelper<Mode> {
impl<Mode: Copy + Clone, TransitionState: Default> ModeHelper<Mode, TransitionState> {
pub fn new(init_mode: Mode, timeout: Duration) -> Self {
Self {
current: init_mode,
@@ -124,7 +125,12 @@ impl<Mode: Copy + Clone> ModeHelper<Mode> {
pub fn start(&mut self, target: Mode) {
self.target = Some(target);
self.transition_start = Some(Instant::now());
self.transition_state = TransitionState::Idle;
self.transition_state = TransitionState::default();
}
#[inline]
pub fn transition_active(&self) -> bool {
self.target.is_some()
}
pub fn timed_out(&self) -> bool {
@@ -146,6 +152,7 @@ impl<Mode: Copy + Clone> ModeHelper<Mode> {
} else {
self.target = None;
}
self.transition_state = Default::default();
self.transition_start = None;
}
}
+62 -40
View File
@@ -1,13 +1,13 @@
use std::{
net::{IpAddr, SocketAddr},
sync::{mpsc, Arc, Mutex},
sync::{Arc, Mutex, mpsc},
thread,
time::Duration,
};
use eps::{
pcdu::{PcduHandler, SerialInterfaceDummy, SerialInterfaceToSim, SerialSimInterfaceWrapper},
PowerSwitchHelper,
pcdu::{PcduHandler, SerialInterfaceDummy, SerialInterfaceToSim, SerialSimInterfaceWrapper},
};
use interface::{
sim_client_udp::create_sim_client,
@@ -24,10 +24,13 @@ use satrs::{
request::{GenericMessage, MessageMetadata},
spacepackets::time::cds::CdsTime,
};
use satrs_example::config::{
components::NO_SENDER,
tasks::{FREQ_MS_AOCS, FREQ_MS_CONTROLLER, FREQ_MS_UDP_TMTC, SIM_CLIENT_IDLE_DELAY_MS},
OBSW_SERVER_ADDR, PACKET_ID_VALIDATOR, SERVER_PORT,
use satrs_example::{
TmtcQueues,
config::{
OBSW_SERVER_ADDR, PACKET_ID_VALIDATOR, SERVER_PORT,
components::NO_SENDER,
tasks::{FREQ_MS_AOCS, FREQ_MS_CONTROLLER, FREQ_MS_UDP_TMTC, SIM_CLIENT_IDLE_DELAY_MS},
},
};
use tmtc::sender::TmTcSender;
use tmtc::{tc_source::TcSourceTask, tm_sink::TmSink};
@@ -66,6 +69,7 @@ fn main() {
let (mgm_0_handler_tc_tx, mgm_0_handler_tc_rx) = mpsc::sync_channel(10);
let (mgm_1_handler_tc_tx, mgm_1_handler_tc_rx) = mpsc::sync_channel(10);
let (_mgm_assembly_tc_tx, mgm_assembly_tc_rx) = mpsc::sync_channel(10);
let (pcdu_handler_tc_tx, pcdu_handler_tc_rx) = mpsc::sync_channel(30);
let (controller_tc_tx, controller_tc_rx) = mpsc::sync_channel(10);
@@ -145,25 +149,27 @@ fn main() {
sim_client
.add_reply_recipient(satrs_minisim::SimComponent::Mgm1Lis3Mdl, mgm_1_sim_reply_tx);
(
mgm::SpiInterface::Sim(mgm::SpiSimInterface {
mgm::SpiCommunication::Sim(mgm::SpiSimInterface {
sim_request_tx: sim_request_tx.clone(),
sim_reply_rx: mgm_0_sim_reply_rx,
}),
mgm::SpiInterface::Sim(mgm::SpiSimInterface {
mgm::SpiCommunication::Sim(mgm::SpiSimInterface {
sim_request_tx: sim_request_tx.clone(),
sim_reply_rx: mgm_1_sim_reply_rx,
}),
)
} else {
(
mgm::SpiInterface::Dummy(mgm::SpiDummyInterface::default()),
mgm::SpiInterface::Dummy(mgm::SpiDummyInterface::default()),
mgm::SpiCommunication::Dummy(mgm::SpiDummyInterface::default()),
mgm::SpiCommunication::Dummy(mgm::SpiDummyInterface::default()),
)
};
let mut mgm_0_handler = mgm::MgmHandlerLis3Mdl::new(
mgm::MgmId::_0,
mgm_0_handler_tc_rx,
tm_sink_tx.clone(),
TmtcQueues {
tc_rx: mgm_0_handler_tc_rx,
tm_tx: tm_sink_tx.clone(),
},
switch_helper.clone(),
mgm_0_spi_interface,
shared_mgm_0_set,
@@ -174,8 +180,10 @@ fn main() {
);
let mut mgm_1_handler = mgm::MgmHandlerLis3Mdl::new(
mgm::MgmId::_1,
mgm_1_handler_tc_rx,
tm_sink_tx.clone(),
TmtcQueues {
tc_rx: mgm_1_handler_tc_rx,
tm_tx: tm_sink_tx.clone(),
},
switch_helper.clone(),
mgm_1_spi_interface,
shared_mgm_1_set,
@@ -193,6 +201,10 @@ fn main() {
request_tx_queues: [mgm_0_mode_request_tx, mgm_1_mode_request_tx],
report_rx_queues: [mgm_0_mode_report_rx, mgm_1_mode_report_rx],
},
TmtcQueues {
tc_rx: mgm_assembly_tc_rx,
tm_tx: tm_sink_tx.clone(),
},
);
let pcdu_serial_interface = if let Some(sim_client) = opt_sim_client.as_mut() {
@@ -251,8 +263,10 @@ fn main() {
info!("Starting TM funnel task");
let jh_tm_funnel = thread::Builder::new()
.name("TM SINK".to_string())
.spawn(move || loop {
tm_sink.operation();
.spawn(move || {
loop {
tm_sink.operation();
}
})
.unwrap();
@@ -262,9 +276,11 @@ fn main() {
opt_jh_sim_client = Some(
thread::Builder::new()
.name("SIM ADAPTER".to_string())
.spawn(move || loop {
if sim_client.operation() == HandlingStatus::Empty {
std::thread::sleep(Duration::from_millis(SIM_CLIENT_IDLE_DELAY_MS));
.spawn(move || {
loop {
if sim_client.operation() == HandlingStatus::Empty {
std::thread::sleep(Duration::from_millis(SIM_CLIENT_IDLE_DELAY_MS));
}
}
})
.unwrap(),
@@ -274,39 +290,45 @@ fn main() {
info!("Starting AOCS thread");
let jh_aocs = thread::Builder::new()
.name("AOCS".to_string())
.spawn(move || loop {
mgm_0_handler.periodic_operation();
mgm_1_handler.periodic_operation();
mgm_assembly.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_AOCS));
.spawn(move || {
loop {
mgm_0_handler.periodic_operation();
mgm_1_handler.periodic_operation();
mgm_assembly.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_AOCS));
}
})
.unwrap();
info!("Starting EPS thread");
let jh_eps = thread::Builder::new()
.name("EPS".to_string())
.spawn(move || loop {
// TODO: We should introduce something like a fixed timeslot helper to allow a more
// declarative API. It would also be very useful for the AOCS task.
//
// TODO: The fixed timeslot handler exists.. use it.
// TODO: Why not just use sync code in the PCDU handler, and fully delay there?
pcdu_handler.periodic_operation(crate::eps::pcdu::OpCode::RegularOp);
thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(crate::eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(crate::eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(300));
.spawn(move || {
loop {
// TODO: We should introduce something like a fixed timeslot helper to allow a more
// declarative API. It would also be very useful for the AOCS task.
//
// TODO: The fixed timeslot handler exists.. use it.
// TODO: Why not just use sync code in the PCDU handler, and fully delay there?
pcdu_handler.periodic_operation(crate::eps::pcdu::OpCode::RegularOp);
thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(crate::eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(crate::eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(300));
}
})
.unwrap();
info!("Starting controller thread");
let jh_controller_thread = thread::Builder::new()
.name("CTRL".to_string())
.spawn(move || loop {
controller.periodic_operation();
event_manager.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_CONTROLLER));
.spawn(move || {
loop {
controller.periodic_operation();
event_manager.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_CONTROLLER));
}
})
.unwrap();
+1 -1
View File
@@ -1,9 +1,9 @@
use std::{cell::RefCell, collections::VecDeque, sync::mpsc};
use satrs::{
ComponentId,
queue::GenericSendError,
tmtc::{PacketAsVec, PacketHandler},
ComponentId,
};
#[derive(Default, Debug, Clone)]
+1 -1
View File
@@ -1,4 +1,4 @@
use models::{ccsds::CcsdsTcPacketOwned, ComponentId, TcHeader};
use models::{ComponentId, TcHeader, ccsds::CcsdsTcPacketOwned};
use satrs::{
pus::HandlingStatus,
spacepackets::{CcsdsPacketReader, ChecksumType},