continue
This commit is contained in:
@ -45,6 +45,7 @@ pub mod action;
|
||||
pub mod hk;
|
||||
pub mod mode;
|
||||
pub mod params;
|
||||
pub mod subsystem;
|
||||
|
||||
pub use spacepackets;
|
||||
|
||||
|
@ -15,23 +15,168 @@ pub enum TableEntryType {
|
||||
Sequence,
|
||||
}
|
||||
|
||||
pub struct ModeTableEntry {
|
||||
/// Common fields required for both target and sequence table entries.
|
||||
///
|
||||
/// The most important parameters here are the target ID which this entry belongs to, and the mode
|
||||
/// and submode the entry either will be commanded to for sequence table entries or which will be
|
||||
/// monitored for target table entries.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ModeTableEntryCommon {
|
||||
/// Name of respective table entry.
|
||||
pub name: &'static str,
|
||||
/// Target channel ID.
|
||||
pub channel_id: ComponentId,
|
||||
/// Target component ID.
|
||||
pub target_id: ComponentId,
|
||||
/// Has a different meaning depending on whether this is a sequence table or a target table.
|
||||
///
|
||||
/// - For sequence tables, this denotes the mode which will be commanded
|
||||
/// - For target tables, this is the mode which the target children should have and which
|
||||
/// might be monitored depending on configuration.
|
||||
pub mode_submode: ModeAndSubmode,
|
||||
/// This mask allows to specify multiple allowed submodes for a given mode.
|
||||
pub allowed_submode_mask: Option<Submode>,
|
||||
}
|
||||
|
||||
impl ModeTableEntryCommon {
|
||||
pub fn set_allowed_submode_mask(&mut self, mask: Submode) {
|
||||
self.allowed_submode_mask = Some(mask);
|
||||
}
|
||||
|
||||
pub fn allowed_submode_mask(&self) -> Option<Submode> {
|
||||
self.allowed_submode_mask
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry for the target tables.
|
||||
#[derive(Debug)]
|
||||
pub struct TargetTableEntry {
|
||||
pub common: ModeTableEntryCommon,
|
||||
pub monitor_state: bool,
|
||||
}
|
||||
|
||||
impl TargetTableEntry {
|
||||
pub fn new(
|
||||
name: &'static str,
|
||||
target_id: ComponentId,
|
||||
mode_submode: ModeAndSubmode,
|
||||
monitor_state: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
common: ModeTableEntryCommon {
|
||||
name,
|
||||
target_id,
|
||||
mode_submode,
|
||||
allowed_submode_mask: None,
|
||||
},
|
||||
monitor_state,
|
||||
}
|
||||
}
|
||||
|
||||
delegate::delegate! {
|
||||
to self.common {
|
||||
pub fn set_allowed_submode_mask(&mut self, mask: Submode);
|
||||
pub fn allowed_submode_mask(&self) -> Option<Submode>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TargetTableMapValue {
|
||||
/// Name for a given mode table entry.
|
||||
pub name: &'static str,
|
||||
/// These are the rows of the a target table.
|
||||
pub entries: Vec<TargetTableEntry>,
|
||||
}
|
||||
|
||||
impl TargetTableMapValue {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
entries: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_entry(&mut self, entry: TargetTableEntry) {
|
||||
self.entries.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry for the sequence tables.
|
||||
///
|
||||
/// The `check_success` field instructs the mode sequence executor to verify that the
|
||||
/// target mode was actually reached before executing the next sequence.
|
||||
pub struct SequenceTableEntry {
|
||||
pub common: ModeTableEntryCommon,
|
||||
pub check_success: bool,
|
||||
}
|
||||
|
||||
pub struct ModeTableMapValue {
|
||||
/// Name for a given mode table entry.
|
||||
pub name: &'static str,
|
||||
pub entries: Vec<ModeTableEntry>,
|
||||
impl SequenceTableEntry {
|
||||
pub fn new(
|
||||
name: &'static str,
|
||||
target_id: ComponentId,
|
||||
mode_submode: ModeAndSubmode,
|
||||
check_success: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
common: ModeTableEntryCommon {
|
||||
name,
|
||||
target_id,
|
||||
mode_submode,
|
||||
allowed_submode_mask: None,
|
||||
},
|
||||
check_success,
|
||||
}
|
||||
}
|
||||
|
||||
delegate::delegate! {
|
||||
to self.common {
|
||||
pub fn set_allowed_submode_mask(&mut self, mask: Submode);
|
||||
pub fn allowed_submode_mask(&self) -> Option<Submode>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ModeTable = HashMap<Mode, ModeTableMapValue>;
|
||||
pub struct SequenceTableMapTable {
|
||||
/// Name for a given mode sequence.
|
||||
pub name: &'static str,
|
||||
/// These are the rows of the a sequence table.
|
||||
pub entries: Vec<SequenceTableEntry>,
|
||||
}
|
||||
|
||||
impl SequenceTableMapTable {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
entries: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_entry(&mut self, entry: SequenceTableEntry) {
|
||||
self.entries.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SequenceTableMapValue {
|
||||
/// Name for a given mode sequence.
|
||||
pub name: &'static str,
|
||||
/// Each sequence can consists of multiple sequences that are executed consecutively.
|
||||
pub entries: Vec<SequenceTableMapTable>,
|
||||
}
|
||||
|
||||
impl SequenceTableMapValue {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
entries: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_sequence_table(&mut self, entry: SequenceTableMapTable) {
|
||||
self.entries.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TargetModeTable(pub HashMap<Mode, TargetTableMapValue>);
|
||||
pub struct SequenceModeTable(pub HashMap<Mode, SequenceTableMapValue>);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {}
|
||||
|
134
satrs/src/subsystem.rs
Normal file
134
satrs/src/subsystem.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use crate::{
|
||||
mode::{Mode, ModeAndSubmode, ModeRequest, ModeRequestSender},
|
||||
mode_tree::{SequenceModeTable, SequenceTableMapTable, SequenceTableMapValue},
|
||||
queue::GenericTargetedMessagingError,
|
||||
request::RequestId,
|
||||
ComponentId,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum SequenceExecutionHelperStates {
|
||||
Idle,
|
||||
AwaitingCheckSuccess,
|
||||
Done,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SequenceExecutionHelper {
|
||||
target_mode: Mode,
|
||||
state: SequenceExecutionHelperStates,
|
||||
request_id: RequestId,
|
||||
current_sequence_index: Option<usize>,
|
||||
}
|
||||
|
||||
pub trait CheckSuccessProvider {
|
||||
fn mode_request_requires_success_check(
|
||||
&mut self,
|
||||
target_id: ComponentId,
|
||||
target_mode: ModeAndSubmode,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SequenceHandlerResult {
|
||||
SequenceDone,
|
||||
SequenceStepDone,
|
||||
AwaitingSuccessCheck,
|
||||
}
|
||||
|
||||
impl SequenceExecutionHelper {
|
||||
pub fn new(
|
||||
mode: Mode,
|
||||
request_id: RequestId,
|
||||
sequence_table: &SequenceModeTable,
|
||||
) -> Option<Self> {
|
||||
if !sequence_table.0.contains_key(&mode) {
|
||||
return None;
|
||||
}
|
||||
Some(Self {
|
||||
target_mode: mode,
|
||||
state: SequenceExecutionHelperStates::Idle,
|
||||
request_id,
|
||||
current_sequence_index: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn confirm_sequence_done(&mut self) {
|
||||
if let SequenceExecutionHelperStates::AwaitingCheckSuccess = self.state {
|
||||
self.state = SequenceExecutionHelperStates::Idle;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
&mut self,
|
||||
table: &SequenceModeTable,
|
||||
sender: &impl ModeRequestSender,
|
||||
) -> Result<SequenceHandlerResult, GenericTargetedMessagingError> {
|
||||
if self.state == SequenceExecutionHelperStates::AwaitingCheckSuccess {
|
||||
return Ok(SequenceHandlerResult::AwaitingSuccessCheck);
|
||||
}
|
||||
match self.current_sequence_index {
|
||||
Some(idx) => {
|
||||
// Execute the sequence.
|
||||
let seq_table_value = table.0.get(&self.target_mode).unwrap();
|
||||
self.execute_sequence_and_map_to_result(seq_table_value, idx, sender)
|
||||
}
|
||||
None => {
|
||||
// Find the first sequence
|
||||
let seq_table_value = table.0.get(&self.target_mode).unwrap();
|
||||
if seq_table_value.entries.is_empty() {
|
||||
Ok(SequenceHandlerResult::SequenceDone)
|
||||
} else {
|
||||
self.current_sequence_index = Some(0);
|
||||
self.execute_sequence_and_map_to_result(seq_table_value, 0, sender)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute_sequence_and_map_to_result(
|
||||
&mut self,
|
||||
seq_table_value: &SequenceTableMapValue,
|
||||
sequence_idx: usize,
|
||||
sender: &impl ModeRequestSender,
|
||||
) -> Result<SequenceHandlerResult, GenericTargetedMessagingError> {
|
||||
if Self::execute_sequence(
|
||||
self.request_id,
|
||||
&seq_table_value.entries[sequence_idx],
|
||||
sender,
|
||||
)? {
|
||||
self.state = SequenceExecutionHelperStates::AwaitingCheckSuccess;
|
||||
Ok(SequenceHandlerResult::AwaitingSuccessCheck)
|
||||
} else if seq_table_value.entries.len() - 1 == sequence_idx {
|
||||
return Ok(SequenceHandlerResult::SequenceDone);
|
||||
} else {
|
||||
self.current_sequence_index = Some(sequence_idx + 1);
|
||||
return Ok(SequenceHandlerResult::SequenceStepDone);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute_sequence(
|
||||
request_id: RequestId,
|
||||
map_table: &SequenceTableMapTable,
|
||||
//sequence_idx: usize,
|
||||
sender: &impl ModeRequestSender,
|
||||
) -> Result<bool, GenericTargetedMessagingError> {
|
||||
let mut some_succes_check_required = false;
|
||||
for entry in &map_table.entries {
|
||||
sender.send_mode_request(
|
||||
request_id,
|
||||
entry.common.target_id,
|
||||
ModeRequest::SetMode(entry.common.mode_submode),
|
||||
)?;
|
||||
if entry.check_success {
|
||||
some_succes_check_required = true;
|
||||
}
|
||||
}
|
||||
Ok(some_succes_check_required)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
pub struct SatSystem {}
|
||||
}
|
Reference in New Issue
Block a user