This commit is contained in:
2024-11-21 18:35:16 +01:00
parent ed266a11f6
commit 3569fce95e
4 changed files with 421 additions and 50 deletions

View File

@ -45,6 +45,7 @@ pub mod action;
pub mod hk;
pub mod mode;
pub mod params;
pub mod subsystem;
pub use spacepackets;

View File

@ -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
View 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 {}
}