re-work ACS
This commit is contained in:
@@ -152,11 +152,18 @@ pub trait Message {
|
||||
fn message_type(&self) -> MessageType;
|
||||
}
|
||||
|
||||
/// Generic device mode which covers the requirements of most devices.
|
||||
///
|
||||
/// The states are related both to the physical and the logical state of the device. Some
|
||||
/// device handlers control the power supply of their own device and an off state might also
|
||||
/// mean that the device is physically off.
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum DeviceMode {
|
||||
Off = 0,
|
||||
On = 1,
|
||||
/// Normal operation mode where periodic polling might be done as well.
|
||||
Normal = 2,
|
||||
Unknown = 3,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
|
||||
@@ -51,10 +51,16 @@ pub mod response {
|
||||
MgmData(MgmData),
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
|
||||
pub enum ModeFailure {
|
||||
Timeout,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
|
||||
pub enum Response {
|
||||
Ok,
|
||||
Hk(HkResponse),
|
||||
ModeFailure(ModeFailure),
|
||||
}
|
||||
|
||||
impl Response {
|
||||
@@ -62,6 +68,7 @@ pub mod response {
|
||||
match self {
|
||||
Response::Ok => crate::MessageType::Verification,
|
||||
Response::Hk(_hk_response) => crate::MessageType::Hk,
|
||||
Response::ModeFailure(_mode_failure) => crate::MessageType::Mode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
use models::ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned};
|
||||
use models::mgm::response::ModeFailure;
|
||||
use models::mgm::MgmData;
|
||||
use models::pcdu::SwitchId;
|
||||
use models::{mgm, ComponentId, DeviceMode, HkRequestType};
|
||||
use satrs::spacepackets::CcsdsPacketIdAndPsc;
|
||||
use satrs_example::{HkHelperSingleSet, TimestampHelper};
|
||||
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_minisim::acs::MgmRequestLis3Mdl;
|
||||
use satrs_minisim::{SerializableSimMsgPayload, SimReply, SimRequest};
|
||||
use std::fmt::Debug;
|
||||
use std::sync::mpsc::{self};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
use satrs::request::MessageMetadata;
|
||||
|
||||
use crate::acs::mgm_assembly;
|
||||
use crate::ccsds::pack_ccsds_tm_packet_for_now;
|
||||
use crate::eps::PowerSwitchHelper;
|
||||
use crate::spi::SpiInterface;
|
||||
|
||||
pub const NR_OF_DATA_AND_CFG_REGISTERS: usize = 14;
|
||||
|
||||
@@ -28,12 +26,38 @@ pub const X_LOWBYTE_IDX: usize = 9;
|
||||
pub const Y_LOWBYTE_IDX: usize = 11;
|
||||
pub const Z_LOWBYTE_IDX: usize = 13;
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
pub enum TransitionState {
|
||||
#[default]
|
||||
Idle,
|
||||
PowerSwitching,
|
||||
Done,
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum MgmId {
|
||||
_0,
|
||||
_1,
|
||||
}
|
||||
|
||||
impl MgmId {
|
||||
pub const fn str(&self) -> &str {
|
||||
match self {
|
||||
MgmId::_0 => "MGM 0",
|
||||
MgmId::_1 => "MGM 1",
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn component_id(&self) -> ComponentId {
|
||||
match self {
|
||||
MgmId::_0 => ComponentId::AcsMgm0,
|
||||
MgmId::_1 => ComponentId::AcsMgm1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ModeRequest {
|
||||
SetMode(DeviceMode),
|
||||
ReadMode,
|
||||
}
|
||||
|
||||
pub enum ModeReport {
|
||||
Mode(DeviceMode),
|
||||
/// Setting a mode timed out.
|
||||
SetModeTimeout,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -41,14 +65,11 @@ pub struct SpiDummyInterface {
|
||||
pub dummy_values: MgmLis3RawValues,
|
||||
}
|
||||
|
||||
impl SpiInterface for SpiDummyInterface {
|
||||
type Error = ();
|
||||
|
||||
fn transfer(&mut self, _tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
|
||||
impl SpiDummyInterface {
|
||||
fn transfer(&mut self, _tx: &[u8], rx: &mut [u8]) {
|
||||
rx[X_LOWBYTE_IDX..X_LOWBYTE_IDX + 2].copy_from_slice(&self.dummy_values.x.to_le_bytes());
|
||||
rx[Y_LOWBYTE_IDX..Y_LOWBYTE_IDX + 2].copy_from_slice(&self.dummy_values.y.to_be_bytes());
|
||||
rx[Z_LOWBYTE_IDX..Z_LOWBYTE_IDX + 2].copy_from_slice(&self.dummy_values.z.to_be_bytes());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,11 +78,9 @@ pub struct SpiSimInterface {
|
||||
pub sim_reply_rx: mpsc::Receiver<SimReply>,
|
||||
}
|
||||
|
||||
impl SpiInterface for SpiSimInterface {
|
||||
type Error = ();
|
||||
|
||||
impl SpiSimInterface {
|
||||
// Right now, we only support requesting sensor data and not configuration of the sensor.
|
||||
fn transfer(&mut self, _tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
|
||||
fn transfer(&mut self, _tx: &[u8], rx: &mut [u8]) {
|
||||
let mgm_sensor_request = MgmRequestLis3Mdl::RequestSensorData;
|
||||
if let Err(e) = self
|
||||
.sim_request_tx
|
||||
@@ -84,22 +103,19 @@ impl SpiInterface for SpiSimInterface {
|
||||
log::warn!("MGM LIS3 SIM reply timeout: {e}");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SpiSimInterfaceWrapper {
|
||||
pub enum SpiCommunication {
|
||||
Dummy(SpiDummyInterface),
|
||||
Sim(SpiSimInterface),
|
||||
}
|
||||
|
||||
impl SpiInterface for SpiSimInterfaceWrapper {
|
||||
type Error = ();
|
||||
|
||||
fn transfer(&mut self, tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
|
||||
impl SpiCommunication {
|
||||
fn transfer(&mut self, tx: &[u8], rx: &mut [u8]) {
|
||||
match self {
|
||||
SpiSimInterfaceWrapper::Dummy(dummy) => dummy.transfer(tx, rx),
|
||||
SpiSimInterfaceWrapper::Sim(sim_if) => sim_if.transfer(tx, rx),
|
||||
SpiCommunication::Dummy(dummy) => dummy.transfer(tx, rx),
|
||||
SpiCommunication::Sim(sim_if) => sim_if.transfer(tx, rx),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,67 +126,45 @@ pub struct BufWrapper {
|
||||
rx_buf: [u8; 32],
|
||||
}
|
||||
|
||||
pub struct ModeHelpers {
|
||||
current: DeviceMode,
|
||||
target: Option<DeviceMode>,
|
||||
tc_id: Option<CcsdsPacketIdAndPsc>,
|
||||
transition_state: TransitionState,
|
||||
}
|
||||
|
||||
impl Default for ModeHelpers {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
current: DeviceMode::Off,
|
||||
target: Default::default(),
|
||||
tc_id: Default::default(),
|
||||
transition_state: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper component for communication with a parent component, which is usually as assembly.
|
||||
pub struct ModeLeafHelper {
|
||||
pub request_rx: mpsc::Receiver<super::mgm_assembly::ModeRequest>,
|
||||
pub report_tx: mpsc::SyncSender<super::mgm_assembly::ModeReport>,
|
||||
pub request_rx: mpsc::Receiver<ModeRequest>,
|
||||
pub report_tx: mpsc::SyncSender<ModeReport>,
|
||||
}
|
||||
|
||||
/// Example MGM device handler strongly based on the LIS3MDL MEMS device.
|
||||
pub struct MgmHandlerLis3Mdl<ComInterface: SpiInterface> {
|
||||
id: ComponentId,
|
||||
dev_str: &'static str,
|
||||
pub struct MgmHandlerLis3Mdl {
|
||||
id: MgmId,
|
||||
tc_rx: mpsc::Receiver<CcsdsTcPacketOwned>,
|
||||
tm_tx: mpsc::SyncSender<CcsdsTmPacketOwned>,
|
||||
switch_helper: PowerSwitchHelper,
|
||||
pub com_interface: ComInterface,
|
||||
pub com_interface: SpiCommunication,
|
||||
shared_mgm_set: Arc<Mutex<MgmData>>,
|
||||
buffers: BufWrapper,
|
||||
stamp_helper: TimestampHelper,
|
||||
hk_helper: HkHelperSingleSet,
|
||||
mode_helpers: ModeHelpers,
|
||||
mode_helpers: ModeHelper<DeviceMode>,
|
||||
mode_leaf_helper: ModeLeafHelper,
|
||||
}
|
||||
|
||||
impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
impl MgmHandlerLis3Mdl {
|
||||
pub fn new(
|
||||
id: ComponentId,
|
||||
dev_str: &'static str,
|
||||
id: MgmId,
|
||||
tc_rx: mpsc::Receiver<CcsdsTcPacketOwned>,
|
||||
tm_tx: mpsc::SyncSender<CcsdsTmPacketOwned>,
|
||||
switch_helper: PowerSwitchHelper,
|
||||
com_interface: ComInterface,
|
||||
com_interface: SpiCommunication,
|
||||
shared_mgm_set: Arc<Mutex<MgmData>>,
|
||||
mode_leaf_helper: ModeLeafHelper,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
dev_str,
|
||||
tc_rx,
|
||||
tm_tx,
|
||||
switch_helper,
|
||||
com_interface,
|
||||
shared_mgm_set,
|
||||
mode_helpers: ModeHelpers::default(),
|
||||
mode_helpers: ModeHelper::new(DeviceMode::Off, Duration::from_millis(200)),
|
||||
buffers: BufWrapper::default(),
|
||||
stamp_helper: TimestampHelper::default(),
|
||||
hk_helper: HkHelperSingleSet::new(false, Duration::from_millis(200)),
|
||||
@@ -186,8 +180,8 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
|
||||
#[inline]
|
||||
pub fn switch_id(&self) -> SwitchId {
|
||||
match self.id {
|
||||
ComponentId::AcsMgm0 => SwitchId::Mgm0,
|
||||
ComponentId::AcsMgm1 => SwitchId::Mgm1,
|
||||
MgmId::_0 => SwitchId::Mgm0,
|
||||
MgmId::_1 => SwitchId::Mgm1,
|
||||
_ => panic!("unexpected component id"),
|
||||
}
|
||||
}
|
||||
@@ -207,7 +201,7 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
|
||||
|
||||
// Poll sensor before checking and generating HK.
|
||||
if self.mode() == DeviceMode::Normal {
|
||||
log::trace!("polling LIS3MDL sensor {}", self.dev_str);
|
||||
log::trace!("polling LIS3MDL sensor {}", self.id.str());
|
||||
self.poll_sensor();
|
||||
}
|
||||
|
||||
@@ -261,10 +255,8 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
|
||||
loop {
|
||||
match self.mode_leaf_helper.request_rx.try_recv() {
|
||||
Ok(request) => match request {
|
||||
mgm_assembly::ModeRequest::SetMode(device_mode) => {
|
||||
self.start_transition(device_mode, false)
|
||||
}
|
||||
mgm_assembly::ModeRequest::ReadMode => self.report_mode_to_parent(),
|
||||
ModeRequest::SetMode(device_mode) => self.start_transition(device_mode, false),
|
||||
ModeRequest::ReadMode => self.report_mode_to_parent(),
|
||||
},
|
||||
Err(e) => match e {
|
||||
std::sync::mpsc::TryRecvError::Empty => break,
|
||||
@@ -281,7 +273,7 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
|
||||
tc_id: Option<CcsdsPacketIdAndPsc>,
|
||||
response: mgm::response::Response,
|
||||
) {
|
||||
match pack_ccsds_tm_packet_for_now(self.id, tc_id, &response) {
|
||||
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) {
|
||||
log::warn!("failed to send TM packet: {}", e);
|
||||
@@ -358,12 +350,11 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
|
||||
}
|
||||
|
||||
fn start_transition(&mut self, target_mode: DeviceMode, _forced: bool) {
|
||||
log::info!("{}: transitioning to mode {:?}", self.dev_str, target_mode);
|
||||
log::info!("{}: transitioning to mode {:?}", self.id.str(), target_mode);
|
||||
if target_mode == DeviceMode::Off {
|
||||
self.shared_mgm_set.lock().unwrap().valid = false;
|
||||
}
|
||||
self.mode_helpers.transition_state = TransitionState::Idle;
|
||||
self.mode_helpers.target = Some(target_mode);
|
||||
self.mode_helpers.start(target_mode);
|
||||
}
|
||||
|
||||
pub fn handle_mode_transition(&mut self) {
|
||||
@@ -373,7 +364,6 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
|
||||
let target_mode = self.mode_helpers.target.unwrap();
|
||||
if target_mode == DeviceMode::On || target_mode == DeviceMode::Normal {
|
||||
if self.mode_helpers.transition_state == TransitionState::Idle {
|
||||
// TODO: Switch ID for MGM1..
|
||||
let result = self
|
||||
.switch_helper
|
||||
.send_switch_on_cmd(MessageMetadata::new(0, self.id as u32), self.switch_id());
|
||||
@@ -383,24 +373,38 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
|
||||
}
|
||||
self.mode_helpers.transition_state = TransitionState::PowerSwitching;
|
||||
}
|
||||
if self.mode_helpers.transition_state == TransitionState::PowerSwitching
|
||||
&& self.switch_helper.is_switch_on(self.switch_id())
|
||||
{
|
||||
self.mode_helpers.transition_state = TransitionState::Done;
|
||||
if self.mode_helpers.transition_state == TransitionState::PowerSwitching {
|
||||
if self.switch_helper.is_switch_on(self.switch_id()) {
|
||||
self.mode_helpers.transition_state = TransitionState::Done;
|
||||
} else if self.mode_helpers.timed_out() {
|
||||
self.handle_mode_transition_failure();
|
||||
}
|
||||
}
|
||||
if self.mode_helpers.transition_state == TransitionState::Done {
|
||||
self.mode_helpers.current = self.mode_helpers.target.unwrap();
|
||||
self.handle_mode_reached();
|
||||
self.mode_helpers.transition_state = TransitionState::Idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_mode_transition_failure(&mut self) {
|
||||
self.mode_helpers.finish(false);
|
||||
if let Some(requestor) = self.mode_helpers.tc_id {
|
||||
self.send_telemetry(
|
||||
Some(requestor),
|
||||
mgm::response::Response::ModeFailure(ModeFailure::Timeout),
|
||||
);
|
||||
}
|
||||
self.mode_leaf_helper
|
||||
.report_tx
|
||||
.send(ModeReport::SetModeTimeout)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn handle_mode_reached(&mut self) {
|
||||
self.mode_helpers.target = None;
|
||||
self.mode_helpers.finish(true);
|
||||
log::info!(
|
||||
"{} announcing mode: {:?}",
|
||||
self.dev_str,
|
||||
self.id.str(),
|
||||
self.mode_helpers.current
|
||||
);
|
||||
if let Some(requestor) = self.mode_helpers.tc_id {
|
||||
@@ -413,7 +417,7 @@ impl<ComInterface: SpiInterface> MgmHandlerLis3Mdl<ComInterface> {
|
||||
fn report_mode_to_parent(&self) {
|
||||
self.mode_leaf_helper
|
||||
.report_tx
|
||||
.send(mgm_assembly::ModeReport::Mode(self.mode_helpers.current))
|
||||
.send(ModeReport::Mode(self.mode_helpers.current))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -474,7 +478,7 @@ mod tests {
|
||||
pub next_mgm_data: MgmLis3RawValues,
|
||||
}
|
||||
|
||||
impl SpiInterface for TestSpiInterface {
|
||||
impl SpiCommunication for TestSpiInterface {
|
||||
type Error = ();
|
||||
|
||||
fn transfer(&mut self, _tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error> {
|
||||
@@ -491,8 +495,8 @@ mod tests {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct MgmTestbench {
|
||||
pub assembly_mode_request_tx: mpsc::SyncSender<mgm_assembly::ModeRequest>,
|
||||
pub mode_report_rx: mpsc::Receiver<mgm_assembly::ModeReport>,
|
||||
pub assembly_mode_request_tx: mpsc::SyncSender<ModeRequest>,
|
||||
pub mode_report_rx: mpsc::Receiver<ModeReport>,
|
||||
pub shared_switch_set: SharedSwitchSet,
|
||||
pub tc_tx: mpsc::SyncSender<CcsdsTcPacketOwned>,
|
||||
pub tm_rx: mpsc::Receiver<CcsdsTmPacketOwned>,
|
||||
@@ -517,8 +521,7 @@ mod tests {
|
||||
let switch_map = SwitchSet::new(switch_map);
|
||||
let shared_switch_set = SharedSwitchSet::new(Mutex::new(switch_map));
|
||||
let handler = MgmHandlerLis3Mdl::new(
|
||||
ComponentId::AcsMgm0,
|
||||
"TEST_MGM",
|
||||
MgmId::_0,
|
||||
tc_rx,
|
||||
tm_tx,
|
||||
PowerSwitchHelper::new(switcher_tx, shared_switch_set.clone()),
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
// TODO: Remove dead_code lint as soon as assembly is done.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::sync::mpsc;
|
||||
use std::{sync::mpsc, time::Duration};
|
||||
|
||||
use models::DeviceMode;
|
||||
use satrs_example::ModeHelper;
|
||||
|
||||
pub enum ModeRequest {
|
||||
SetMode(DeviceMode),
|
||||
@@ -13,30 +14,51 @@ pub enum ModeRequest {
|
||||
|
||||
pub enum ModeReport {
|
||||
Mode(DeviceMode),
|
||||
/// Setting a mode timed out.
|
||||
SetModeTimeout,
|
||||
/// An assembly child lost the mode.
|
||||
ChildLostMode,
|
||||
}
|
||||
|
||||
pub struct ParentQueueHelper {
|
||||
pub request_rx: mpsc::Receiver<ModeRequest>,
|
||||
pub report_tx: mpsc::SyncSender<ModeReport>,
|
||||
}
|
||||
|
||||
/// Helper component for communication with a parent component, which is usually as assembly.
|
||||
pub struct QueueHelper {
|
||||
pub request_tx_queues: [mpsc::SyncSender<super::mgm_assembly::ModeRequest>; 2],
|
||||
pub report_rx_queues: [mpsc::Receiver<super::mgm_assembly::ModeReport>; 2],
|
||||
pub struct ChildrenQueueHelper {
|
||||
pub request_tx_queues: [mpsc::SyncSender<super::mgm::ModeRequest>; 2],
|
||||
pub report_rx_queues: [mpsc::Receiver<super::mgm::ModeReport>; 2],
|
||||
}
|
||||
|
||||
/// MGM assembly component.
|
||||
pub struct Assembly {
|
||||
pub(crate) helper: QueueHelper,
|
||||
mode_helper: ModeHelper<DeviceMode>,
|
||||
parent_queues: ParentQueueHelper,
|
||||
pub(crate) children_queues: ChildrenQueueHelper,
|
||||
}
|
||||
|
||||
impl Assembly {
|
||||
pub fn periodic_operation(&mut self) {
|
||||
self.handle_mode_queue();
|
||||
pub fn new(parent_queues: ParentQueueHelper, children_queues: ChildrenQueueHelper) -> Self {
|
||||
Self {
|
||||
mode_helper: ModeHelper::new(DeviceMode::Unknown, Duration::from_millis(200)),
|
||||
parent_queues,
|
||||
children_queues,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_mode_queue(&mut self) {
|
||||
for rx in &mut self.helper.report_rx_queues {
|
||||
pub fn periodic_operation(&mut self) {
|
||||
self.handle_children_mode_queues();
|
||||
}
|
||||
|
||||
pub fn handle_children_mode_queues(&mut self) {
|
||||
for rx in &mut self.children_queues.report_rx_queues {
|
||||
loop {
|
||||
match rx.try_recv() {
|
||||
// TODO: Do something with the report.
|
||||
Ok(report) => match report {
|
||||
ModeReport::Mode(_device_mode) => (),
|
||||
super::mgm::ModeReport::Mode(_device_mode) => todo!(),
|
||||
super::mgm::ModeReport::SetModeTimeout => todo!(),
|
||||
},
|
||||
Err(e) => match e {
|
||||
mpsc::TryRecvError::Empty => break,
|
||||
|
||||
@@ -3,7 +3,7 @@ extern crate alloc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub use models::ComponentId;
|
||||
use satrs::spacepackets::time::cds::CdsTime;
|
||||
use satrs::spacepackets::{time::cds::CdsTime, CcsdsPacketIdAndPsc};
|
||||
|
||||
pub mod config;
|
||||
|
||||
@@ -90,3 +90,62 @@ impl HkHelperSingleSet {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
pub enum TransitionState {
|
||||
#[default]
|
||||
Idle,
|
||||
PowerSwitching,
|
||||
Done,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ModeHelper<Mode> {
|
||||
pub current: Mode,
|
||||
pub target: Option<Mode>,
|
||||
pub tc_id: Option<CcsdsPacketIdAndPsc>,
|
||||
pub transition_start: Option<Instant>,
|
||||
pub timeout: Duration,
|
||||
pub transition_state: TransitionState,
|
||||
}
|
||||
|
||||
impl<Mode: Copy + Clone> ModeHelper<Mode> {
|
||||
pub fn new(init_mode: Mode, timeout: Duration) -> Self {
|
||||
Self {
|
||||
current: init_mode,
|
||||
target: Default::default(),
|
||||
tc_id: Default::default(),
|
||||
transition_start: None,
|
||||
timeout,
|
||||
transition_state: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&mut self, target: Mode) {
|
||||
self.target = Some(target);
|
||||
self.transition_start = Some(Instant::now());
|
||||
self.transition_state = TransitionState::Idle;
|
||||
}
|
||||
|
||||
pub fn timed_out(&self) -> bool {
|
||||
if self.target.is_none() {
|
||||
return false;
|
||||
}
|
||||
if let Some(transition_start) = self.transition_start {
|
||||
return Instant::now() - transition_start >= self.timeout;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn finish(&mut self, success: bool) {
|
||||
if self.target.is_none() {
|
||||
return;
|
||||
}
|
||||
if success {
|
||||
self.current = self.target.take().unwrap();
|
||||
} else {
|
||||
self.target = None;
|
||||
}
|
||||
self.transition_start = None;
|
||||
}
|
||||
}
|
||||
|
||||
+21
-21
@@ -33,12 +33,7 @@ use tmtc::sender::TmTcSender;
|
||||
use tmtc::{tc_source::TcSourceTask, tm_sink::TmSink};
|
||||
|
||||
use crate::{
|
||||
acs::{
|
||||
mgm::{
|
||||
self, MgmHandlerLis3Mdl, SpiDummyInterface, SpiSimInterface, SpiSimInterfaceWrapper,
|
||||
},
|
||||
mgm_assembly,
|
||||
},
|
||||
acs::{mgm, mgm_assembly},
|
||||
control::Controller,
|
||||
eps::pcdu::SwitchSet,
|
||||
event_manager::EventManager,
|
||||
@@ -53,7 +48,6 @@ mod eps;
|
||||
mod event_manager;
|
||||
mod interface;
|
||||
mod logger;
|
||||
mod spi;
|
||||
mod tmtc;
|
||||
|
||||
fn main() {
|
||||
@@ -75,7 +69,11 @@ fn main() {
|
||||
let (pcdu_handler_tc_tx, pcdu_handler_tc_rx) = mpsc::sync_channel(30);
|
||||
let (controller_tc_tx, controller_tc_rx) = mpsc::sync_channel(10);
|
||||
|
||||
// These message handles need to go into the MGM assembly.
|
||||
// These message handles need to go into the MGM assembly and ACS subsystem.
|
||||
let (_mgm_assembly_request_tx, mgm_assembly_request_rx) = mpsc::sync_channel(5);
|
||||
let (mgm_assembly_report_tx, _mgm_assembly_report_rx) = mpsc::sync_channel(5);
|
||||
|
||||
// These message handles need to go into the MGM assembly and MGM devices.
|
||||
let (mgm_0_mode_request_tx, mgm_0_mode_request_rx) = mpsc::sync_channel(5);
|
||||
let (mgm_1_mode_request_tx, mgm_1_mode_request_rx) = mpsc::sync_channel(5);
|
||||
let (mgm_0_mode_report_tx, mgm_0_mode_report_rx) = mpsc::sync_channel(5);
|
||||
@@ -147,24 +145,23 @@ fn main() {
|
||||
sim_client
|
||||
.add_reply_recipient(satrs_minisim::SimComponent::Mgm1Lis3Mdl, mgm_1_sim_reply_tx);
|
||||
(
|
||||
SpiSimInterfaceWrapper::Sim(SpiSimInterface {
|
||||
mgm::SpiInterface::Sim(mgm::SpiSimInterface {
|
||||
sim_request_tx: sim_request_tx.clone(),
|
||||
sim_reply_rx: mgm_0_sim_reply_rx,
|
||||
}),
|
||||
SpiSimInterfaceWrapper::Sim(SpiSimInterface {
|
||||
mgm::SpiInterface::Sim(mgm::SpiSimInterface {
|
||||
sim_request_tx: sim_request_tx.clone(),
|
||||
sim_reply_rx: mgm_1_sim_reply_rx,
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
SpiSimInterfaceWrapper::Dummy(SpiDummyInterface::default()),
|
||||
SpiSimInterfaceWrapper::Dummy(SpiDummyInterface::default()),
|
||||
mgm::SpiInterface::Dummy(mgm::SpiDummyInterface::default()),
|
||||
mgm::SpiInterface::Dummy(mgm::SpiDummyInterface::default()),
|
||||
)
|
||||
};
|
||||
let mut mgm_0_handler = MgmHandlerLis3Mdl::new(
|
||||
ComponentId::AcsMgm0,
|
||||
"MGM_0",
|
||||
let mut mgm_0_handler = mgm::MgmHandlerLis3Mdl::new(
|
||||
mgm::MgmId::_0,
|
||||
mgm_0_handler_tc_rx,
|
||||
tm_sink_tx.clone(),
|
||||
switch_helper.clone(),
|
||||
@@ -175,9 +172,8 @@ fn main() {
|
||||
report_tx: mgm_0_mode_report_tx,
|
||||
},
|
||||
);
|
||||
let mut mgm_1_handler = MgmHandlerLis3Mdl::new(
|
||||
ComponentId::AcsMgm1,
|
||||
"MGM_1",
|
||||
let mut mgm_1_handler = mgm::MgmHandlerLis3Mdl::new(
|
||||
mgm::MgmId::_1,
|
||||
mgm_1_handler_tc_rx,
|
||||
tm_sink_tx.clone(),
|
||||
switch_helper.clone(),
|
||||
@@ -188,12 +184,16 @@ fn main() {
|
||||
report_tx: mgm_1_mode_report_tx,
|
||||
},
|
||||
);
|
||||
let mut mgm_assembly = mgm_assembly::Assembly {
|
||||
helper: mgm_assembly::QueueHelper {
|
||||
let mut mgm_assembly = mgm_assembly::Assembly::new(
|
||||
mgm_assembly::ParentQueueHelper {
|
||||
request_rx: mgm_assembly_request_rx,
|
||||
report_tx: mgm_assembly_report_tx,
|
||||
},
|
||||
mgm_assembly::ChildrenQueueHelper {
|
||||
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],
|
||||
},
|
||||
};
|
||||
);
|
||||
|
||||
let pcdu_serial_interface = if let Some(sim_client) = opt_sim_client.as_mut() {
|
||||
sim_client.add_reply_recipient(satrs_minisim::SimComponent::Pcdu, pcdu_sim_reply_tx);
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
use core::fmt::Debug;
|
||||
|
||||
pub trait SpiInterface {
|
||||
type Error: Debug;
|
||||
fn transfer(&mut self, tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error>;
|
||||
}
|
||||
Reference in New Issue
Block a user