Merge branch 'main' into update-example
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good
This commit is contained in:
commit
bec3b28527
@ -73,7 +73,7 @@ features = ["all"]
|
|||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.spacepackets]
|
[dependencies.spacepackets]
|
||||||
version = "0.7.0"
|
version = "0.8.1"
|
||||||
default-features = false
|
default-features = false
|
||||||
# git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git"
|
# git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git"
|
||||||
# rev = "297cfad22637d3b07a1b27abe56d9a607b5b82a7"
|
# rev = "297cfad22637d3b07a1b27abe56d9a607b5b82a7"
|
||||||
|
@ -8,9 +8,11 @@ use core::time::Duration;
|
|||||||
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::{PusError, PusPacket};
|
use spacepackets::ecss::{PusError, PusPacket, WritablePusPacket};
|
||||||
use spacepackets::time::{CcsdsTimeProvider, TimeReader, TimestampError, UnixTimestamp};
|
use spacepackets::time::{
|
||||||
use spacepackets::CcsdsPacket;
|
CcsdsTimeProvider, TimeReader, TimeWriter, TimestampError, UnixTimestamp,
|
||||||
|
};
|
||||||
|
use spacepackets::{ByteConversionError, CcsdsPacket};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
@ -154,8 +156,9 @@ pub enum ScheduleError {
|
|||||||
StoreError(StoreError),
|
StoreError(StoreError),
|
||||||
TcDataEmpty,
|
TcDataEmpty,
|
||||||
TimestampError(TimestampError),
|
TimestampError(TimestampError),
|
||||||
WrongSubservice,
|
WrongSubservice(u8),
|
||||||
WrongService,
|
WrongService(u8),
|
||||||
|
ByteConversionError(ByteConversionError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ScheduleError {
|
impl Display for ScheduleError {
|
||||||
@ -171,26 +174,29 @@ impl Display for ScheduleError {
|
|||||||
} => {
|
} => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Error: time margin too short, current time: {current_time:?}, time margin: {time_margin:?}, release time: {release_time:?}"
|
"time margin too short, current time: {current_time:?}, time margin: {time_margin:?}, release time: {release_time:?}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ScheduleError::NestedScheduledTc => {
|
ScheduleError::NestedScheduledTc => {
|
||||||
write!(f, "Error: nested scheduling is not allowed")
|
write!(f, "nested scheduling is not allowed")
|
||||||
}
|
}
|
||||||
ScheduleError::StoreError(e) => {
|
ScheduleError::StoreError(e) => {
|
||||||
write!(f, "Store Error: {e}")
|
write!(f, "pus scheduling: {e}")
|
||||||
}
|
}
|
||||||
ScheduleError::TcDataEmpty => {
|
ScheduleError::TcDataEmpty => {
|
||||||
write!(f, "Error: empty Tc Data field")
|
write!(f, "empty TC data field")
|
||||||
}
|
}
|
||||||
ScheduleError::TimestampError(e) => {
|
ScheduleError::TimestampError(e) => {
|
||||||
write!(f, "Timestamp Error: {e}")
|
write!(f, "pus scheduling: {e}")
|
||||||
}
|
}
|
||||||
ScheduleError::WrongService => {
|
ScheduleError::WrongService(srv) => {
|
||||||
write!(f, "Error: Service not 11.")
|
write!(f, "pus scheduling: wrong service number {srv}")
|
||||||
}
|
}
|
||||||
ScheduleError::WrongSubservice => {
|
ScheduleError::WrongSubservice(subsrv) => {
|
||||||
write!(f, "Error: Subservice not 4.")
|
write!(f, "pus scheduling: wrong subservice number {subsrv}")
|
||||||
|
}
|
||||||
|
ScheduleError::ByteConversionError(e) => {
|
||||||
|
write!(f, "pus scheduling: {e}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,24 +204,39 @@ impl Display for ScheduleError {
|
|||||||
|
|
||||||
impl From<PusError> for ScheduleError {
|
impl From<PusError> for ScheduleError {
|
||||||
fn from(e: PusError) -> Self {
|
fn from(e: PusError) -> Self {
|
||||||
ScheduleError::PusError(e)
|
Self::PusError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StoreError> for ScheduleError {
|
impl From<StoreError> for ScheduleError {
|
||||||
fn from(e: StoreError) -> Self {
|
fn from(e: StoreError) -> Self {
|
||||||
ScheduleError::StoreError(e)
|
Self::StoreError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TimestampError> for ScheduleError {
|
impl From<TimestampError> for ScheduleError {
|
||||||
fn from(e: TimestampError) -> Self {
|
fn from(e: TimestampError) -> Self {
|
||||||
ScheduleError::TimestampError(e)
|
Self::TimestampError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<ByteConversionError> for ScheduleError {
|
||||||
|
fn from(e: ByteConversionError) -> Self {
|
||||||
|
Self::ByteConversionError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl Error for ScheduleError {}
|
impl Error for ScheduleError {
|
||||||
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
|
match self {
|
||||||
|
ScheduleError::PusError(e) => Some(e),
|
||||||
|
ScheduleError::StoreError(e) => Some(e),
|
||||||
|
ScheduleError::TimestampError(e) => Some(e),
|
||||||
|
ScheduleError::ByteConversionError(e) => Some(e),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait PusSchedulerInterface {
|
pub trait PusSchedulerInterface {
|
||||||
type TimeProvider: CcsdsTimeProvider + TimeReader;
|
type TimeProvider: CcsdsTimeProvider + TimeReader;
|
||||||
@ -249,10 +270,12 @@ pub trait PusSchedulerInterface {
|
|||||||
pool: &mut (impl PoolProviderMemInPlace + ?Sized),
|
pool: &mut (impl PoolProviderMemInPlace + ?Sized),
|
||||||
) -> Result<TcInfo, ScheduleError> {
|
) -> Result<TcInfo, ScheduleError> {
|
||||||
if PusPacket::service(pus_tc) != 11 {
|
if PusPacket::service(pus_tc) != 11 {
|
||||||
return Err(ScheduleError::WrongService);
|
return Err(ScheduleError::WrongService(PusPacket::service(pus_tc)));
|
||||||
}
|
}
|
||||||
if PusPacket::subservice(pus_tc) != 4 {
|
if PusPacket::subservice(pus_tc) != 4 {
|
||||||
return Err(ScheduleError::WrongSubservice);
|
return Err(ScheduleError::WrongSubservice(PusPacket::subservice(
|
||||||
|
pus_tc,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
if pus_tc.user_data().is_empty() {
|
if pus_tc.user_data().is_empty() {
|
||||||
return Err(ScheduleError::TcDataEmpty);
|
return Err(ScheduleError::TcDataEmpty);
|
||||||
@ -289,6 +312,34 @@ pub trait PusSchedulerInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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, ScheduleError> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub mod alloc_mod {
|
pub mod alloc_mod {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -307,6 +358,19 @@ pub mod alloc_mod {
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::time::SystemTimeError;
|
use std::time::SystemTimeError;
|
||||||
|
|
||||||
|
/// This function is similar to [generate_insert_telecommand_app_data] but returns the application
|
||||||
|
/// data as a [alloc::vec::Vec].
|
||||||
|
pub fn generate_insert_telecommand_app_data_as_vec(
|
||||||
|
release_time: &impl TimeWriter,
|
||||||
|
request: &impl WritablePusPacket,
|
||||||
|
) -> Result<alloc::vec::Vec<u8>, ScheduleError> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
enum DeletionResult {
|
enum DeletionResult {
|
||||||
WithoutStoreDeletion(Option<StoreAddr>),
|
WithoutStoreDeletion(Option<StoreAddr>),
|
||||||
WithStoreDeletion(Result<bool, StoreError>),
|
WithStoreDeletion(Result<bool, StoreError>),
|
||||||
@ -757,7 +821,7 @@ mod tests {
|
|||||||
use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader};
|
use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader};
|
||||||
use spacepackets::ecss::WritablePusPacket;
|
use spacepackets::ecss::WritablePusPacket;
|
||||||
use spacepackets::time::{cds, TimeWriter, UnixTimestamp};
|
use spacepackets::time::{cds, TimeWriter, UnixTimestamp};
|
||||||
use spacepackets::SpHeader;
|
use spacepackets::{PacketId, PacketSequenceCtrl, PacketType, SequenceFlags, SpHeader};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@ -835,7 +899,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic() {
|
fn test_enable_api() {
|
||||||
let mut scheduler =
|
let mut scheduler =
|
||||||
PusScheduler::new(UnixTimestamp::new_only_seconds(0), Duration::from_secs(5));
|
PusScheduler::new(UnixTimestamp::new_only_seconds(0), Duration::from_secs(5));
|
||||||
assert!(scheduler.is_enabled());
|
assert!(scheduler.is_enabled());
|
||||||
@ -846,7 +910,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reset() {
|
fn test_reset() {
|
||||||
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new(vec![(10, 32), (5, 64)]));
|
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new(vec![(10, 32), (5, 64)]));
|
||||||
let mut scheduler =
|
let mut scheduler =
|
||||||
PusScheduler::new(UnixTimestamp::new_only_seconds(0), Duration::from_secs(5));
|
PusScheduler::new(UnixTimestamp::new_only_seconds(0), Duration::from_secs(5));
|
||||||
@ -857,7 +921,7 @@ mod tests {
|
|||||||
scheduler
|
scheduler
|
||||||
.insert_unwrapped_and_stored_tc(
|
.insert_unwrapped_and_stored_tc(
|
||||||
UnixTimestamp::new_only_seconds(100),
|
UnixTimestamp::new_only_seconds(100),
|
||||||
TcInfo::new(tc_info_0.addr.clone(), tc_info_0.request_id),
|
TcInfo::new(tc_info_0.addr, tc_info_0.request_id),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -866,7 +930,7 @@ mod tests {
|
|||||||
scheduler
|
scheduler
|
||||||
.insert_unwrapped_and_stored_tc(
|
.insert_unwrapped_and_stored_tc(
|
||||||
UnixTimestamp::new_only_seconds(200),
|
UnixTimestamp::new_only_seconds(200),
|
||||||
TcInfo::new(tc_info_1.addr.clone(), tc_info_1.request_id),
|
TcInfo::new(tc_info_1.addr, tc_info_1.request_id),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -875,7 +939,7 @@ mod tests {
|
|||||||
scheduler
|
scheduler
|
||||||
.insert_unwrapped_and_stored_tc(
|
.insert_unwrapped_and_stored_tc(
|
||||||
UnixTimestamp::new_only_seconds(300),
|
UnixTimestamp::new_only_seconds(300),
|
||||||
TcInfo::new(tc_info_2.addr().clone(), tc_info_2.request_id()),
|
TcInfo::new(tc_info_2.addr(), tc_info_2.request_id()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -950,7 +1014,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn time() {
|
fn test_time_update() {
|
||||||
let mut scheduler =
|
let mut scheduler =
|
||||||
PusScheduler::new(UnixTimestamp::new_only_seconds(0), Duration::from_secs(5));
|
PusScheduler::new(UnixTimestamp::new_only_seconds(0), Duration::from_secs(5));
|
||||||
let time = UnixTimestamp::new(1, 2).unwrap();
|
let time = UnixTimestamp::new(1, 2).unwrap();
|
||||||
@ -964,7 +1028,7 @@ mod tests {
|
|||||||
expected_store_addrs: Vec<StoreAddr>,
|
expected_store_addrs: Vec<StoreAddr>,
|
||||||
counter: &mut usize,
|
counter: &mut usize,
|
||||||
) {
|
) {
|
||||||
assert_eq!(enabled, true);
|
assert!(enabled);
|
||||||
assert!(expected_store_addrs.contains(store_addr));
|
assert!(expected_store_addrs.contains(store_addr));
|
||||||
*counter += 1;
|
*counter += 1;
|
||||||
}
|
}
|
||||||
@ -974,13 +1038,13 @@ mod tests {
|
|||||||
expected_store_addrs: Vec<StoreAddr>,
|
expected_store_addrs: Vec<StoreAddr>,
|
||||||
counter: &mut usize,
|
counter: &mut usize,
|
||||||
) {
|
) {
|
||||||
assert_eq!(enabled, false);
|
assert!(!enabled);
|
||||||
assert!(expected_store_addrs.contains(store_addr));
|
assert!(expected_store_addrs.contains(store_addr));
|
||||||
*counter += 1;
|
*counter += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn request_id() {
|
fn test_request_id() {
|
||||||
let src_id_to_set = 12;
|
let src_id_to_set = 12;
|
||||||
let apid_to_set = 0x22;
|
let apid_to_set = 0x22;
|
||||||
let seq_count = 105;
|
let seq_count = 105;
|
||||||
@ -998,7 +1062,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn release_basic() {
|
fn test_release_telecommands() {
|
||||||
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new(vec![(10, 32), (5, 64)]));
|
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new(vec![(10, 32), (5, 64)]));
|
||||||
let mut scheduler =
|
let mut scheduler =
|
||||||
PusScheduler::new(UnixTimestamp::new_only_seconds(0), Duration::from_secs(5));
|
PusScheduler::new(UnixTimestamp::new_only_seconds(0), Duration::from_secs(5));
|
||||||
@ -1290,7 +1354,9 @@ mod tests {
|
|||||||
assert!(err.is_err());
|
assert!(err.is_err());
|
||||||
let err = err.unwrap_err();
|
let err = err.unwrap_err();
|
||||||
match err {
|
match err {
|
||||||
ScheduleError::WrongService => {}
|
ScheduleError::WrongService(wrong_service) => {
|
||||||
|
assert_eq!(wrong_service, 12);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("unexpected error")
|
panic!("unexpected error")
|
||||||
}
|
}
|
||||||
@ -1311,7 +1377,9 @@ mod tests {
|
|||||||
assert!(err.is_err());
|
assert!(err.is_err());
|
||||||
let err = err.unwrap_err();
|
let err = err.unwrap_err();
|
||||||
match err {
|
match err {
|
||||||
ScheduleError::WrongSubservice => {}
|
ScheduleError::WrongSubservice(wrong_subsrv) => {
|
||||||
|
assert_eq!(wrong_subsrv, 5);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("unexpected error")
|
panic!("unexpected error")
|
||||||
}
|
}
|
||||||
@ -1487,7 +1555,7 @@ mod tests {
|
|||||||
let del_res =
|
let del_res =
|
||||||
scheduler.delete_by_request_id_and_from_pool(&tc_info_0.request_id(), &mut pool);
|
scheduler.delete_by_request_id_and_from_pool(&tc_info_0.request_id(), &mut pool);
|
||||||
assert!(del_res.is_ok());
|
assert!(del_res.is_ok());
|
||||||
assert_eq!(del_res.unwrap(), true);
|
assert!(del_res.unwrap());
|
||||||
assert!(!pool.has_element_at(&tc_info_0.addr()).unwrap());
|
assert!(!pool.has_element_at(&tc_info_0.addr()).unwrap());
|
||||||
assert_eq!(scheduler.num_scheduled_telecommands(), 0);
|
assert_eq!(scheduler.num_scheduled_telecommands(), 0);
|
||||||
}
|
}
|
||||||
@ -1804,4 +1872,109 @@ mod tests {
|
|||||||
assert!(!pool.has_element_at(&cmd_1_to_delete.addr()).unwrap());
|
assert!(!pool.has_element_at(&cmd_1_to_delete.addr()).unwrap());
|
||||||
assert!(pool.has_element_at(&cmd_out_of_range_1.addr()).unwrap());
|
assert!(pool.has_element_at(&cmd_out_of_range_1.addr()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_release_without_deletion() {
|
||||||
|
let mut pool = StaticMemoryPool::new(StaticPoolConfig::new(vec![(10, 32), (5, 64)]));
|
||||||
|
let mut scheduler =
|
||||||
|
PusScheduler::new(UnixTimestamp::new_only_seconds(0), Duration::from_secs(5));
|
||||||
|
|
||||||
|
let mut buf: [u8; 32] = [0; 32];
|
||||||
|
let tc_info_0 = ping_tc_to_store(&mut pool, &mut buf, 0, None);
|
||||||
|
|
||||||
|
scheduler
|
||||||
|
.insert_unwrapped_and_stored_tc(UnixTimestamp::new_only_seconds(100), tc_info_0)
|
||||||
|
.expect("insertion failed");
|
||||||
|
|
||||||
|
let tc_info_1 = ping_tc_to_store(&mut pool, &mut buf, 1, None);
|
||||||
|
scheduler
|
||||||
|
.insert_unwrapped_and_stored_tc(UnixTimestamp::new_only_seconds(200), tc_info_1)
|
||||||
|
.expect("insertion failed");
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
let mut test_closure_1 = |boolvar: bool, tc_info: &TcInfo, _tc: &[u8]| {
|
||||||
|
common_check(
|
||||||
|
boolvar,
|
||||||
|
&tc_info.addr,
|
||||||
|
vec![tc_info_0.addr(), tc_info_1.addr()],
|
||||||
|
&mut i,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
scheduler.update_time(UnixTimestamp::new_only_seconds(205));
|
||||||
|
|
||||||
|
let tc_info_vec = scheduler
|
||||||
|
.release_telecommands_no_deletion(&mut test_closure_1, &pool)
|
||||||
|
.expect("deletion failed");
|
||||||
|
assert_eq!(tc_info_vec[0], tc_info_0);
|
||||||
|
assert_eq!(tc_info_vec[1], tc_info_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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(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_byte_conv_error() {
|
||||||
|
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(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; 16] = [0; 16];
|
||||||
|
let result = generate_insert_telecommand_app_data(&mut buf, &time_writer, &ping_tc);
|
||||||
|
assert!(result.is_err());
|
||||||
|
let error = result.unwrap_err();
|
||||||
|
if let ScheduleError::ByteConversionError(ByteConversionError::ToSliceTooSmall {
|
||||||
|
found,
|
||||||
|
expected,
|
||||||
|
}) = error
|
||||||
|
{
|
||||||
|
assert_eq!(found, 16);
|
||||||
|
assert_eq!(
|
||||||
|
expected,
|
||||||
|
2 + time_writer.len_written() + ping_tc.len_written()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("unexpected error {error}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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(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