This commit is contained in:
parent
7c32b1c905
commit
145b50347d
@ -2,13 +2,14 @@
|
|||||||
//!
|
//!
|
||||||
//! The core data structure of this module is the [PusScheduler]. This structure can be used
|
//! The core data structure of this module is the [PusScheduler]. This structure can be used
|
||||||
//! to perform the scheduling of telecommands like specified in the ECSS standard.
|
//! to perform the scheduling of telecommands like specified in the ECSS standard.
|
||||||
use core::fmt::Debug;
|
use core::fmt::{Debug, Display, Formatter};
|
||||||
|
use core::time::Duration;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use spacepackets::ecss::scheduling::TimeWindowType;
|
use spacepackets::ecss::scheduling::TimeWindowType;
|
||||||
use spacepackets::ecss::tc::{GenericPusTcSecondaryHeader, IsPusTelecommand, PusTcReader};
|
use spacepackets::ecss::tc::{GenericPusTcSecondaryHeader, IsPusTelecommand, PusTcReader};
|
||||||
use spacepackets::ecss::PusPacket;
|
use spacepackets::ecss::{PusError, PusPacket};
|
||||||
use spacepackets::time::{CcsdsTimeProvider, TimeReader, UnixTimestamp};
|
use spacepackets::time::{CcsdsTimeProvider, TimeReader, TimestampError, UnixTimestamp};
|
||||||
use spacepackets::CcsdsPacket;
|
use spacepackets::CcsdsPacket;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
@ -136,6 +137,86 @@ impl<TimeProvider: CcsdsTimeProvider + Clone> TimeWindow<TimeProvider> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
pub enum ScheduleError {
|
||||||
|
PusError(PusError),
|
||||||
|
/// The release time is within the time-margin added on top of the current time.
|
||||||
|
/// The first parameter is the current time, the second one the time margin, and the third one
|
||||||
|
/// the release time.
|
||||||
|
ReleaseTimeInTimeMargin {
|
||||||
|
current_time: UnixTimestamp,
|
||||||
|
time_margin: Duration,
|
||||||
|
release_time: UnixTimestamp,
|
||||||
|
},
|
||||||
|
/// Nested time-tagged commands are not allowed.
|
||||||
|
NestedScheduledTc,
|
||||||
|
StoreError(StoreError),
|
||||||
|
TcDataEmpty,
|
||||||
|
TimestampError(TimestampError),
|
||||||
|
WrongSubservice,
|
||||||
|
WrongService,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ScheduleError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ScheduleError::PusError(e) => {
|
||||||
|
write!(f, "Pus Error: {e}")
|
||||||
|
}
|
||||||
|
ScheduleError::ReleaseTimeInTimeMargin {
|
||||||
|
current_time,
|
||||||
|
time_margin,
|
||||||
|
release_time,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Error: time margin too short, current time: {current_time:?}, time margin: {time_margin:?}, release time: {release_time:?}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ScheduleError::NestedScheduledTc => {
|
||||||
|
write!(f, "Error: nested scheduling is not allowed")
|
||||||
|
}
|
||||||
|
ScheduleError::StoreError(e) => {
|
||||||
|
write!(f, "Store Error: {e}")
|
||||||
|
}
|
||||||
|
ScheduleError::TcDataEmpty => {
|
||||||
|
write!(f, "Error: empty Tc Data field")
|
||||||
|
}
|
||||||
|
ScheduleError::TimestampError(e) => {
|
||||||
|
write!(f, "Timestamp Error: {e}")
|
||||||
|
}
|
||||||
|
ScheduleError::WrongService => {
|
||||||
|
write!(f, "Error: Service not 11.")
|
||||||
|
}
|
||||||
|
ScheduleError::WrongSubservice => {
|
||||||
|
write!(f, "Error: Subservice not 4.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PusError> for ScheduleError {
|
||||||
|
fn from(e: PusError) -> Self {
|
||||||
|
ScheduleError::PusError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StoreError> for ScheduleError {
|
||||||
|
fn from(e: StoreError) -> Self {
|
||||||
|
ScheduleError::StoreError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TimestampError> for ScheduleError {
|
||||||
|
fn from(e: TimestampError) -> Self {
|
||||||
|
ScheduleError::TimestampError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl Error for ScheduleError {}
|
||||||
|
|
||||||
pub trait PusSchedulerInterface {
|
pub trait PusSchedulerInterface {
|
||||||
type TimeProvider: CcsdsTimeProvider + TimeReader;
|
type TimeProvider: CcsdsTimeProvider + TimeReader;
|
||||||
|
|
||||||
@ -213,13 +294,12 @@ pub mod alloc_mod {
|
|||||||
use alloc::collections::BTreeMap;
|
use alloc::collections::BTreeMap;
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::fmt::{Display, Formatter};
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use spacepackets::ecss::scheduling::TimeWindowType;
|
use spacepackets::ecss::scheduling::TimeWindowType;
|
||||||
use spacepackets::ecss::tc::{PusTc, PusTcReader};
|
use spacepackets::ecss::tc::{PusTc, PusTcReader};
|
||||||
use spacepackets::ecss::{PusError, PusPacket};
|
use spacepackets::ecss::PusPacket;
|
||||||
use spacepackets::time::cds::DaysLen24Bits;
|
use spacepackets::time::cds::DaysLen24Bits;
|
||||||
use spacepackets::time::{cds, CcsdsTimeProvider, TimestampError, UnixTimestamp};
|
use spacepackets::time::{cds, CcsdsTimeProvider, UnixTimestamp};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::time::SystemTimeError;
|
use std::time::SystemTimeError;
|
||||||
@ -229,78 +309,6 @@ pub mod alloc_mod {
|
|||||||
WithStoreDeletion(Result<bool, StoreError>),
|
WithStoreDeletion(Result<bool, StoreError>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
pub enum ScheduleError {
|
|
||||||
PusError(PusError),
|
|
||||||
/// The release time is within the time-margin added on top of the current time.
|
|
||||||
/// The first parameter is the current time, the second one the time margin, and the third one
|
|
||||||
/// the release time.
|
|
||||||
ReleaseTimeInTimeMargin(UnixTimestamp, Duration, UnixTimestamp),
|
|
||||||
/// Nested time-tagged commands are not allowed.
|
|
||||||
NestedScheduledTc,
|
|
||||||
StoreError(StoreError),
|
|
||||||
TcDataEmpty,
|
|
||||||
TimestampError(TimestampError),
|
|
||||||
WrongSubservice,
|
|
||||||
WrongService,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ScheduleError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
|
||||||
match self {
|
|
||||||
ScheduleError::PusError(e) => {
|
|
||||||
write!(f, "Pus Error: {e}")
|
|
||||||
}
|
|
||||||
ScheduleError::ReleaseTimeInTimeMargin(current_time, margin, timestamp) => {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Error: time margin too short, current time: {current_time:?}, time margin: {margin:?}, release time: {timestamp:?}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ScheduleError::NestedScheduledTc => {
|
|
||||||
write!(f, "Error: nested scheduling is not allowed")
|
|
||||||
}
|
|
||||||
ScheduleError::StoreError(e) => {
|
|
||||||
write!(f, "Store Error: {e}")
|
|
||||||
}
|
|
||||||
ScheduleError::TcDataEmpty => {
|
|
||||||
write!(f, "Error: empty Tc Data field")
|
|
||||||
}
|
|
||||||
ScheduleError::TimestampError(e) => {
|
|
||||||
write!(f, "Timestamp Error: {e}")
|
|
||||||
}
|
|
||||||
ScheduleError::WrongService => {
|
|
||||||
write!(f, "Error: Service not 11.")
|
|
||||||
}
|
|
||||||
ScheduleError::WrongSubservice => {
|
|
||||||
write!(f, "Error: Subservice not 4.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PusError> for ScheduleError {
|
|
||||||
fn from(e: PusError) -> Self {
|
|
||||||
ScheduleError::PusError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<StoreError> for ScheduleError {
|
|
||||||
fn from(e: StoreError) -> Self {
|
|
||||||
ScheduleError::StoreError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TimestampError> for ScheduleError {
|
|
||||||
fn from(e: TimestampError) -> Self {
|
|
||||||
ScheduleError::TimestampError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl Error for ScheduleError {}
|
|
||||||
|
|
||||||
/// This is the core data structure for scheduling PUS telecommands with [alloc] support.
|
/// This is the core data structure for scheduling PUS telecommands with [alloc] support.
|
||||||
///
|
///
|
||||||
/// It is assumed that the actual telecommand data is stored in a separate TC pool offering
|
/// It is assumed that the actual telecommand data is stored in a separate TC pool offering
|
||||||
@ -378,11 +386,11 @@ pub mod alloc_mod {
|
|||||||
info: TcInfo,
|
info: TcInfo,
|
||||||
) -> Result<(), ScheduleError> {
|
) -> Result<(), ScheduleError> {
|
||||||
if time_stamp < self.current_time + self.time_margin {
|
if time_stamp < self.current_time + self.time_margin {
|
||||||
return Err(ScheduleError::ReleaseTimeInTimeMargin(
|
return Err(ScheduleError::ReleaseTimeInTimeMargin {
|
||||||
self.current_time,
|
current_time: self.current_time,
|
||||||
self.time_margin,
|
time_margin: self.time_margin,
|
||||||
time_stamp,
|
release_time: time_stamp,
|
||||||
));
|
});
|
||||||
}
|
}
|
||||||
match self.tc_map.entry(time_stamp) {
|
match self.tc_map.entry(time_stamp) {
|
||||||
Entry::Vacant(e) => {
|
Entry::Vacant(e) => {
|
||||||
@ -672,11 +680,11 @@ pub mod alloc_mod {
|
|||||||
info: TcInfo,
|
info: TcInfo,
|
||||||
) -> Result<(), ScheduleError> {
|
) -> Result<(), ScheduleError> {
|
||||||
if time_stamp < self.current_time + self.time_margin {
|
if time_stamp < self.current_time + self.time_margin {
|
||||||
return Err(ScheduleError::ReleaseTimeInTimeMargin(
|
return Err(ScheduleError::ReleaseTimeInTimeMargin {
|
||||||
self.current_time,
|
current_time: self.current_time,
|
||||||
self.time_margin,
|
time_margin: self.time_margin,
|
||||||
time_stamp,
|
release_time: time_stamp,
|
||||||
));
|
});
|
||||||
}
|
}
|
||||||
match self.tc_map.entry(time_stamp) {
|
match self.tc_map.entry(time_stamp) {
|
||||||
Entry::Vacant(e) => {
|
Entry::Vacant(e) => {
|
||||||
@ -1324,9 +1332,13 @@ mod tests {
|
|||||||
assert!(insert_res.is_err());
|
assert!(insert_res.is_err());
|
||||||
let err = insert_res.unwrap_err();
|
let err = insert_res.unwrap_err();
|
||||||
match err {
|
match err {
|
||||||
ScheduleError::ReleaseTimeInTimeMargin(curr_time, margin, release_time) => {
|
ScheduleError::ReleaseTimeInTimeMargin {
|
||||||
assert_eq!(curr_time, UnixTimestamp::new_only_seconds(0));
|
current_time,
|
||||||
assert_eq!(margin, Duration::from_secs(5));
|
time_margin,
|
||||||
|
release_time,
|
||||||
|
} => {
|
||||||
|
assert_eq!(current_time, UnixTimestamp::new_only_seconds(0));
|
||||||
|
assert_eq!(time_margin, Duration::from_secs(5));
|
||||||
assert_eq!(release_time, UnixTimestamp::new_only_seconds(4));
|
assert_eq!(release_time, UnixTimestamp::new_only_seconds(4));
|
||||||
}
|
}
|
||||||
_ => panic!("unexepcted error {err}"),
|
_ => panic!("unexepcted error {err}"),
|
||||||
|
Loading…
Reference in New Issue
Block a user