start integrating new susbystem commanding helper
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq, num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum Mode {
|
||||
Passive,
|
||||
Safe,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use core::str::FromStr;
|
||||
|
||||
use num_enum::TryFromPrimitive as _;
|
||||
use satrs::mode::ModeRaw;
|
||||
|
||||
use crate::DeviceMode;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -11,6 +14,32 @@ pub enum Mode {
|
||||
NoModeKeeping,
|
||||
}
|
||||
|
||||
impl From<Mode> for ModeRaw {
|
||||
fn from(value: Mode) -> Self {
|
||||
match value {
|
||||
Mode::Device(device_mode) => device_mode.into(),
|
||||
Mode::NoModeKeeping => 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ModeRaw> for Mode {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: ModeRaw) -> Result<Self, Self::Error> {
|
||||
match DeviceMode::try_from_primitive(value) {
|
||||
Ok(val) => Ok(Mode::Device(val)),
|
||||
Err(_) => {
|
||||
if value == 5 {
|
||||
Ok(Mode::NoModeKeeping)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Mode {
|
||||
type Err = ();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq, num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum Mode {
|
||||
Off,
|
||||
Normal,
|
||||
|
||||
@@ -29,8 +29,10 @@ pub enum ComponentId {
|
||||
|
||||
AcsSubsystem,
|
||||
AcsMgmAssembly,
|
||||
AcsController,
|
||||
AcsMgm0,
|
||||
AcsMgm1,
|
||||
AcsMgt,
|
||||
|
||||
EpsSubsystem,
|
||||
EpsPcdu,
|
||||
@@ -159,7 +161,8 @@ pub trait Message {
|
||||
/// 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)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone, num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum DeviceMode {
|
||||
Off = 0,
|
||||
On = 1,
|
||||
|
||||
@@ -7,7 +7,12 @@ use models::{
|
||||
ComponentId,
|
||||
acs::subsystem::{Mode, response},
|
||||
};
|
||||
use satrs::spacepackets::CcsdsPacketIdAndPsc;
|
||||
use satrs::{
|
||||
mode::ModeRaw,
|
||||
mode_tree::{ModeStoreProvider, ModeStoreVec, SequenceModeTables, TargetModeTables},
|
||||
spacepackets::CcsdsPacketIdAndPsc,
|
||||
subsystem::SubsystemCommandingHelper,
|
||||
};
|
||||
use satrs_example::{ModeHelper, TmtcQueues};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -114,6 +119,7 @@ pub struct Subsystem {
|
||||
mode_request_senders: ModeRequestSenders,
|
||||
mode_report_receivers: ModeReportReceivers,
|
||||
tmtc_queues: TmtcQueues,
|
||||
subsystem_helper: SubsystemCommandingHelper,
|
||||
}
|
||||
|
||||
impl Subsystem {
|
||||
@@ -124,6 +130,24 @@ impl Subsystem {
|
||||
mode_report_receivers: ModeReportReceivers,
|
||||
tmtc_queues: TmtcQueues,
|
||||
) -> Self {
|
||||
let mut mode_store_vec = ModeStoreVec::default();
|
||||
mode_store_vec.add_component(
|
||||
ComponentId::AcsMgmAssembly as satrs::ComponentId,
|
||||
models::acs::mgm_assembly::Mode::NoModeKeeping.into(),
|
||||
);
|
||||
mode_store_vec.add_component(
|
||||
ComponentId::AcsController as satrs::ComponentId,
|
||||
models::acs::ctrl::Mode::Passive.into(),
|
||||
);
|
||||
mode_store_vec.add_component(
|
||||
ComponentId::AcsMgt as satrs::ComponentId,
|
||||
models::acs::mgt::Mode::Off.into(),
|
||||
);
|
||||
|
||||
let mut target_tables = TargetModeTables::default();
|
||||
|
||||
let mut sequence_tables = SequenceModeTables::default();
|
||||
|
||||
Self {
|
||||
mode_helper: ModeHelper::new(
|
||||
models::acs::subsystem::Mode::Off,
|
||||
@@ -134,6 +158,11 @@ impl Subsystem {
|
||||
mode_report_receivers,
|
||||
tmtc_queues,
|
||||
transition_step: 0,
|
||||
subsystem_helper: SubsystemCommandingHelper::new(
|
||||
mode_store_vec,
|
||||
target_tables,
|
||||
sequence_tables,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ impl ModeStoreValue {
|
||||
}
|
||||
|
||||
pub trait SequenceTableProvider {
|
||||
fn sequence_at_index(&self, index: usize) -> Option<&[SequenceTableEntry]>;
|
||||
fn sequence_at_index(&self, index: u8) -> Option<&[SequenceTableEntry]>;
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
|
||||
+34
-42
@@ -1,3 +1,5 @@
|
||||
use arbitrary_int::{traits::Integer as _, u24};
|
||||
|
||||
use crate::{
|
||||
ComponentId,
|
||||
mode_tree::{
|
||||
@@ -40,8 +42,6 @@ pub struct ModeDoesNotExistError(ModeRaw);
|
||||
pub enum StartSequenceError {
|
||||
#[error("mode {0} does not exist")]
|
||||
ModeDoesNotExist(#[from] ModeDoesNotExistError),
|
||||
#[error("invalid request ID")]
|
||||
InvalidRequestId(RequestId),
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
@@ -60,8 +60,8 @@ pub struct SequenceExecutionHelper {
|
||||
target_mode: Option<ModeRaw>,
|
||||
state: SequenceExecutionHelperState,
|
||||
request_id: Option<RequestId>,
|
||||
current_sequence_index: Option<usize>,
|
||||
last_sequence_index: Option<usize>,
|
||||
current_sequence_index: Option<u8>,
|
||||
last_sequence_index: Option<u8>,
|
||||
}
|
||||
|
||||
impl Default for SequenceExecutionHelper {
|
||||
@@ -123,17 +123,20 @@ impl SequenceExecutionHelper {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `table` - This table contains the sequence tables to reach the mode previously loaded
|
||||
/// with [Self::load]
|
||||
/// * `sender` - The sender to send mode requests to the components
|
||||
/// * `sequence_table_provider` - This table contains the sequence tables to reach the mode
|
||||
/// previously loaded with [Self::load]
|
||||
/// * `children_mode_store` - The mode store vector to keep track of the mode states of
|
||||
/// children components
|
||||
/// * `mode_request_handler` - A function which is called to send out mode requests to the
|
||||
/// children or cache the required requests so they can be sent after the function call.
|
||||
pub fn run<F: FnMut(ComponentId, ModeRaw)>(
|
||||
&mut self,
|
||||
sequence_table_provider: &impl SequenceTableProvider,
|
||||
children_mode_store: &mut impl ModeStoreProvider,
|
||||
mode_request_handler: F,
|
||||
) -> Result<ModeCommandingResult, InvalidSequenceIndexError> {
|
||||
// TODO: Check whether sequence table length is larger than 255. Improbable, but let's
|
||||
// solve this cleanly.
|
||||
if self.state == SequenceExecutionHelperState::Idle {
|
||||
return Ok(ModeCommandingResult::Done);
|
||||
}
|
||||
@@ -211,7 +214,7 @@ impl SequenceExecutionHelper {
|
||||
self.state == SequenceExecutionHelperState::AwaitingSuccessCheck
|
||||
}
|
||||
|
||||
pub fn current_sequence_index(&self) -> Option<usize> {
|
||||
pub fn current_sequence_index(&self) -> Option<u8> {
|
||||
self.current_sequence_index
|
||||
}
|
||||
|
||||
@@ -224,7 +227,7 @@ impl SequenceExecutionHelper {
|
||||
/// It is also called by the [Self::run] method of this helper.
|
||||
pub fn execute_sequence_and_map_to_result(
|
||||
&mut self,
|
||||
sequence_index: usize,
|
||||
sequence_index: u8,
|
||||
table_entries: &[SequenceTableEntry],
|
||||
children_mode_store: &mut impl ModeStoreProvider,
|
||||
mode_request_handler: impl FnMut(ComponentId, ModeRaw),
|
||||
@@ -235,11 +238,11 @@ impl SequenceExecutionHelper {
|
||||
if Self::execute_sequence(table_entries, children_mode_store, mode_request_handler) {
|
||||
self.state = SequenceExecutionHelperState::AwaitingSuccessCheck;
|
||||
ModeCommandingResult::AwaitingSuccessCheck
|
||||
} else if table_entries.len() - 1 == sequence_index {
|
||||
} else if table_entries.len() - 1 == sequence_index as usize {
|
||||
self.state = SequenceExecutionHelperState::Idle;
|
||||
ModeCommandingResult::Done
|
||||
} else {
|
||||
self.current_sequence_index = Some(sequence_index + 1);
|
||||
self.current_sequence_index = Some(sequence_index as u8 + 1);
|
||||
ModeCommandingResult::StepDone
|
||||
}
|
||||
}
|
||||
@@ -310,7 +313,7 @@ pub enum ModeTreeHelperError {
|
||||
#[error("mode command failed")]
|
||||
ModeCommmandFailure {
|
||||
/// Table index of the sequence table entry which failed.
|
||||
seq_table_index: Option<usize>,
|
||||
seq_table_index: Option<u8>,
|
||||
},
|
||||
/// Target mode keeping violation.
|
||||
#[error("target keeping violation")]
|
||||
@@ -323,8 +326,12 @@ pub enum ModeTreeHelperError {
|
||||
/// This is a helper object which can be used by a subsystem component to execute mode sequences
|
||||
/// and perform target keeping.
|
||||
///
|
||||
/// It currently only works on systems with allocation support and it will also allocate at
|
||||
/// run-time.
|
||||
///
|
||||
/// This helper object tries to compose as much data and state information as possible which is
|
||||
/// required for this process.
|
||||
#[derive(Debug)]
|
||||
pub struct SubsystemCommandingHelper {
|
||||
/// State of the helper.
|
||||
state: ModeTreeHelperState,
|
||||
@@ -332,8 +339,9 @@ pub struct SubsystemCommandingHelper {
|
||||
current_mode: ModeRaw,
|
||||
/// This data structure is used to track all mode children.
|
||||
pub children_mode_store: ModeStoreVec,
|
||||
/// This field is set when a mode sequence is executed. It is used to determine whether mode
|
||||
/// replies are relevant for reply awaition logic.
|
||||
/// Sequence counter used to generate unique request IDs.
|
||||
sequence_counter: u24,
|
||||
/// Active internal request ID, whic his built from the sequence counter and sequence index.
|
||||
active_internal_request_id: Option<RequestId>,
|
||||
/// The primary data structure to keep the target state information for subsystem
|
||||
/// [modes][ModeRaw]. it specifies the mode each child should have for a certain subsystem mode
|
||||
@@ -351,6 +359,7 @@ impl Default for SubsystemCommandingHelper {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
current_mode: u32::MAX,
|
||||
sequence_counter: u24::ZERO,
|
||||
state: Default::default(),
|
||||
children_mode_store: Default::default(),
|
||||
active_internal_request_id: None,
|
||||
@@ -382,6 +391,7 @@ impl SubsystemCommandingHelper {
|
||||
state: ModeTreeHelperState::Idle,
|
||||
children_mode_store,
|
||||
active_internal_request_id: None,
|
||||
sequence_counter: u24::ZERO,
|
||||
target_tables,
|
||||
sequence_tables,
|
||||
seq_exec_helper: Default::default(),
|
||||
@@ -396,18 +406,14 @@ impl SubsystemCommandingHelper {
|
||||
self.current_mode
|
||||
}
|
||||
|
||||
pub fn request_id(&self) -> Option<RequestId> {
|
||||
self.active_internal_request_id.map(|v| v >> 8)
|
||||
}
|
||||
|
||||
/// This returns the internal request ID, which is the regular [Self::request_id] specified
|
||||
/// by the user shifter 8 to the right and then increment with the current sequence commanding
|
||||
/// by the user shifted 8 to the right and then increment with the current sequence commanding
|
||||
/// step. The value can still be retrieved because it might be required for reply verification.
|
||||
///
|
||||
/// The state machine specifies this request ID for all mode commands related to the
|
||||
/// current step of sequence commanding.
|
||||
pub fn internal_request_id(&self) -> Option<RequestId> {
|
||||
self.active_internal_request_id
|
||||
fn internal_request_id(&self, sequence_index: u8) -> RequestId {
|
||||
(self.sequence_counter.as_u32() << 8) | sequence_index as u32
|
||||
}
|
||||
|
||||
/// Retrieve the fallback mode for the current mode of the subsystem by trying to retrieve
|
||||
@@ -448,23 +454,10 @@ impl SubsystemCommandingHelper {
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `mode` - The mode to command
|
||||
/// - `request_id` - Request ID associated with the command sequence. The value of this value
|
||||
/// should not be larger than the maximum possible value for 24 bits: (2 ^ 24) - 1 = 16777215
|
||||
/// because 8 bits are reserved for internal sequence index tracking.
|
||||
pub fn start_command_sequence(
|
||||
&mut self,
|
||||
mode: ModeRaw,
|
||||
request_id: RequestId,
|
||||
) -> Result<(), StartSequenceError> {
|
||||
if request_id > 2_u32.pow(24) - 1 {
|
||||
return Err(StartSequenceError::InvalidRequestId(request_id));
|
||||
}
|
||||
self.active_internal_request_id = Some(request_id << 8);
|
||||
self.seq_exec_helper.load(
|
||||
mode,
|
||||
self.active_internal_request_id.unwrap(),
|
||||
&self.sequence_tables,
|
||||
)?;
|
||||
pub fn start_command_sequence(&mut self, mode: ModeRaw) -> Result<(), StartSequenceError> {
|
||||
self.sequence_counter = self.sequence_counter.wrapping_add(u24::new(1));
|
||||
self.seq_exec_helper
|
||||
.load(mode, self.internal_request_id(0), &self.sequence_tables)?;
|
||||
self.state = ModeTreeHelperState::ModeCommanding;
|
||||
Ok(())
|
||||
}
|
||||
@@ -574,10 +567,9 @@ impl SubsystemCommandingHelper {
|
||||
}
|
||||
|
||||
fn update_internal_req_id(&mut self) {
|
||||
let new_internal_req_id = (self.request_id().unwrap() << 8)
|
||||
| self.seq_exec_helper.current_sequence_index().unwrap() as u32;
|
||||
self.seq_exec_helper.set_request_id(new_internal_req_id);
|
||||
self.active_internal_request_id = Some(new_internal_req_id);
|
||||
self.seq_exec_helper.set_request_id(
|
||||
self.internal_request_id(self.seq_exec_helper.current_sequence_index().unwrap() as u8),
|
||||
);
|
||||
}
|
||||
|
||||
// Handles a mode reply message and returns whether the reply completes a step of sequence
|
||||
|
||||
Reference in New Issue
Block a user