add ECSS TC scheduling helper API #59
@ -1,8 +1,18 @@
|
||||
//! PUS Service 11 Scheduling
|
||||
use core::fmt::Display;
|
||||
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
time::{TimeWriter, TimestampError},
|
||||
util::ToBeBytes,
|
||||
ByteConversionError,
|
||||
};
|
||||
|
||||
use super::{PusError, WritablePusPacket};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, IntoPrimitive, TryFromPrimitive)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[repr(u8)]
|
||||
@ -73,11 +83,103 @@ pub enum TimeWindowType {
|
||||
ToTimeTag = 3,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum ScheduleTcGenerationError {
|
||||
ByteConversionError(ByteConversionError),
|
||||
TimestampError(TimestampError),
|
||||
PusError(PusError),
|
||||
}
|
||||
|
||||
impl From<ByteConversionError> for ScheduleTcGenerationError {
|
||||
fn from(error: ByteConversionError) -> Self {
|
||||
Self::ByteConversionError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TimestampError> for ScheduleTcGenerationError {
|
||||
fn from(error: TimestampError) -> Self {
|
||||
Self::TimestampError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PusError> for ScheduleTcGenerationError {
|
||||
fn from(error: PusError) -> Self {
|
||||
Self::PusError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ScheduleTcGenerationError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let const_str = "pus schedule tc generation:";
|
||||
match self {
|
||||
Self::PusError(e) => {
|
||||
write!(f, "{const_str} {e}")
|
||||
}
|
||||
Self::ByteConversionError(e) => {
|
||||
write!(f, "{const_str} {e}")
|
||||
}
|
||||
Self::TimestampError(e) => {
|
||||
write!(f, "{const_str} {e}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for ScheduleTcGenerationError {}
|
||||
|
||||
/// Helper function to generate the application data for a PUS telecommand to insert an
|
||||
/// activity into a time-based schedule according to ECSS-E-ST-70-41C 8.11.2.4
|
||||
///
|
||||
/// Please note that the N field is set to a [u16] unsigned bytefield with the value 1.
|
||||
pub fn generate_insert_telecommand_app_data(
|
||||
buf: &mut [u8],
|
||||
release_time: &impl TimeWriter,
|
||||
request: &impl WritablePusPacket,
|
||||
) -> Result<usize, ScheduleTcGenerationError> {
|
||||
let required_len = 2 + release_time.len_written() + request.len_written();
|
||||
if required_len > buf.len() {
|
||||
return Err(ByteConversionError::ToSliceTooSmall {
|
||||
found: buf.len(),
|
||||
expected: required_len,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
let mut current_len = 0;
|
||||
let n = 1_u16;
|
||||
buf[current_len..current_len + 2].copy_from_slice(&n.to_be_bytes());
|
||||
current_len += 2;
|
||||
current_len += release_time
|
||||
.write_to_bytes(&mut buf[current_len..current_len + release_time.len_written()])?;
|
||||
current_len +=
|
||||
request.write_to_bytes(&mut buf[current_len..current_len + request.len_written()])?;
|
||||
Ok(current_len)
|
||||
}
|
||||
|
||||
/// This function is similar to [generate_insert_telecommand_app_data] but returns the application
|
||||
/// data as a [alloc::vec::Vec].
|
||||
#[cfg(feature = "alloc")]
|
||||
pub fn generate_insert_telecommand_app_data_as_vec(
|
||||
release_time: &impl TimeWriter,
|
||||
request: &impl WritablePusPacket,
|
||||
) -> Result<alloc::vec::Vec<u8>, ScheduleTcGenerationError> {
|
||||
let mut vec = alloc::vec::Vec::new();
|
||||
vec.extend_from_slice(&1_u16.to_be_bytes());
|
||||
vec.append(&mut release_time.to_vec()?);
|
||||
vec.append(&mut request.to_vec()?);
|
||||
Ok(vec)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[cfg(feature = "serde")]
|
||||
use crate::tests::generic_serde_test;
|
||||
use crate::{
|
||||
ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader},
|
||||
time::cds,
|
||||
PacketId, PacketSequenceCtrl, PacketType, SpHeader,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_bool_conv_0() {
|
||||
@ -122,4 +224,43 @@ mod tests {
|
||||
fn test_serde_time_window_type() {
|
||||
generic_serde_test(TimeWindowType::SelectAll);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_insert_app_data_test() {
|
||||
let time_writer = cds::TimeProvider::new_with_u16_days(1, 1);
|
||||
let mut sph = SpHeader::new(
|
||||
PacketId::const_new(PacketType::Tc, true, 0x002),
|
||||
PacketSequenceCtrl::const_new(crate::SequenceFlags::Unsegmented, 5),
|
||||
0,
|
||||
);
|
||||
let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
|
||||
let ping_tc = PusTcCreator::new_no_app_data(&mut sph, sec_header, true);
|
||||
let mut buf: [u8; 64] = [0; 64];
|
||||
let result = generate_insert_telecommand_app_data(&mut buf, &time_writer, &ping_tc);
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), 2 + 7 + ping_tc.len_written());
|
||||
let n = u16::from_be_bytes(buf[0..2].try_into().unwrap());
|
||||
assert_eq!(n, 1);
|
||||
let time_reader = cds::TimeProvider::from_bytes_with_u16_days(&buf[2..2 + 7]).unwrap();
|
||||
assert_eq!(time_reader, time_writer);
|
||||
let pus_tc_reader = PusTcReader::new(&buf[9..]).unwrap().0;
|
||||
assert_eq!(pus_tc_reader, ping_tc);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_insert_app_data_test_as_vec() {
|
||||
let time_writer = cds::TimeProvider::new_with_u16_days(1, 1);
|
||||
let mut sph = SpHeader::new(
|
||||
PacketId::const_new(PacketType::Tc, true, 0x002),
|
||||
PacketSequenceCtrl::const_new(crate::SequenceFlags::Unsegmented, 5),
|
||||
0,
|
||||
);
|
||||
let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
|
||||
let ping_tc = PusTcCreator::new_no_app_data(&mut sph, sec_header, true);
|
||||
let mut buf: [u8; 64] = [0; 64];
|
||||
generate_insert_telecommand_app_data(&mut buf, &time_writer, &ping_tc).unwrap();
|
||||
let vec = generate_insert_telecommand_app_data_as_vec(&time_writer, &ping_tc)
|
||||
.expect("vec generation failed");
|
||||
assert_eq!(&buf[..vec.len()], vec);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user