diff --git a/satrs/src/ccsds/scheduler.rs b/satrs/src/ccsds/scheduler.rs index 5cfbb6d..664d1d5 100644 --- a/satrs/src/ccsds/scheduler.rs +++ b/satrs/src/ccsds/scheduler.rs @@ -301,32 +301,29 @@ pub mod alloc_mod { /// Delete all telecommands scheduled in a time window. /// - /// Returns whether any telecommands were deleted. - pub fn delete_from_start_to_end( - &mut self, - start_time: UnixTime, - end_time: UnixTime, - ) -> bool { + /// The range includes the start time but excludes the end time. Returns whether any + /// telecommands were deleted. + pub fn delete_in_time_window(&mut self, start_time: UnixTime, end_time: UnixTime) -> bool { let len_before = self.tc_map.len(); - self.tc_map.retain(|k, _| k < &start_time || k > &end_time); + self.tc_map.retain(|k, _| k < &start_time || k >= &end_time); self.tc_map.len() < len_before } - /// Delete all scheduled telecommands starting from a given time. + /// Delete all scheduled telecommands scheduled after or at a given time. /// /// Returns whether any telecommands were deleted. - pub fn delete_from_start(&mut self, start_time: UnixTime) -> bool { + pub fn delete_all_starting_at(&mut self, start_time: UnixTime) -> bool { let len_before = self.tc_map.len(); self.tc_map.retain(|k, _| k < &start_time); self.tc_map.len() < len_before } - /// Delete all scheduled telecommands scheduled before a given time. + /// Delete all scheduled telecommands scheduled before but not equal to a given time. /// /// Returns whether any telecommands were deleted. - pub fn delete_until_end(&mut self, end_time: UnixTime) -> bool { + pub fn delete_all_before(&mut self, end_time: UnixTime) -> bool { let len_before = self.tc_map.len(); - self.tc_map.retain(|k, _| k > &end_time); + self.tc_map.retain(|k, _| k >= &end_time); self.tc_map.len() < len_before } @@ -339,16 +336,21 @@ pub mod alloc_mod { #[cfg(test)] mod tests { - use arbitrary_int::u11; + use arbitrary_int::{traits::Integer, u11, u14}; use spacepackets::{ CcsdsPacketCreatorOwned, CcsdsPacketReader, ChecksumType, SpacePacketHeader, }; use super::*; - fn test_tc(app_data: &[u8]) -> CcsdsPacketCreatorOwned { + fn test_tc(app_data: &[u8], seq_count: u14) -> CcsdsPacketCreatorOwned { CcsdsPacketCreatorOwned::new( - SpacePacketHeader::new_from_apid(u11::new(0x1)), + SpacePacketHeader::new_for_tc( + u11::new(0x1), + spacepackets::SequenceFlags::Unsegmented, + seq_count, + 0, + ), spacepackets::PacketType::Tc, app_data, Some(ChecksumType::WithCrc16), @@ -403,7 +405,7 @@ mod tests { Limits::new(Some(100), Some(1024)), Duration::from_millis(1000), ); - let test_tc = test_tc(&[1, 2, 3]); + let test_tc = test_tc(&[1, 2, 3], u14::ZERO); let test_tc_raw = test_tc.to_vec(); let reader = CcsdsPacketReader::new(&test_tc_raw, Some(ChecksumType::WithCrc16)).unwrap(); scheduler @@ -440,9 +442,9 @@ mod tests { Limits::new(Some(100), Some(1024)), Duration::from_millis(1000), ); - let test_tc = test_tc(&[1, 2, 3]); - let tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&test_tc); - let test_tc_raw = test_tc.to_vec(); + let test_tc_0 = test_tc(&[1, 2, 3], u14::ZERO); + let tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&test_tc_0); + let test_tc_raw = test_tc_0.to_vec(); let reader = CcsdsPacketReader::new(&test_tc_raw, Some(ChecksumType::WithCrc16)).unwrap(); let checksum = reader.checksum(); scheduler @@ -484,15 +486,15 @@ mod tests { } #[test] - fn insert_and_release_multi() { + fn insert_and_release_multi_0() { let unix_time = UnixTime::new(0, 0); let mut scheduler = CcsdsScheduler::new( unix_time, Limits::new(Some(100), Some(1024)), Duration::from_millis(1000), ); - let test_tc_0 = test_tc(&[42]); - let test_tc_1 = test_tc(&[1, 2, 3]); + let test_tc_0 = test_tc(&[42], u14::ZERO); + let test_tc_1 = test_tc(&[1, 2, 3], u14::new(1)); let tc_id_0 = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&test_tc_0); let tc_id_1 = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&test_tc_1); let test_tc_0_raw = test_tc_0.to_vec(); @@ -579,6 +581,85 @@ mod tests { assert_eq!(scheduler.num_of_entries(), 0); } + #[test] + fn insert_and_release_multi_1() { + let unix_time = UnixTime::new(0, 0); + let mut scheduler = CcsdsScheduler::new( + unix_time, + Limits::new(Some(100), Some(1024)), + Duration::from_millis(1000), + ); + let test_tc_0 = test_tc(&[42], u14::ZERO); + let test_tc_1 = test_tc(&[1, 2, 3], u14::new(1)); + let tc_id_0 = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&test_tc_0); + let tc_id_1 = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&test_tc_1); + let test_tc_0_raw = test_tc_0.to_vec(); + let test_tc_1_raw = test_tc_1.to_vec(); + let reader_0 = + CcsdsPacketReader::new(&test_tc_0_raw, Some(ChecksumType::WithCrc16)).unwrap(); + let reader_1 = + CcsdsPacketReader::new(&test_tc_1_raw, Some(ChecksumType::WithCrc16)).unwrap(); + scheduler + .insert_telecommand_with_reader(&reader_0, UnixTime::new(2, 0)) + .unwrap(); + scheduler + .insert_telecommand( + CcsdsSchedulePacketId::new(tc_id_1, reader_1.checksum()), + &test_tc_1_raw, + UnixTime::new(5, 0), + ) + .unwrap(); + assert_eq!(scheduler.current_fill_count().packets, 2); + assert_eq!( + scheduler.current_fill_count().bytes, + test_tc_0_raw.len() + test_tc_1_raw.len() + ); + assert_eq!(scheduler.num_of_entries(), 2); + assert_eq!( + scheduler + .telecommands_to_release() + .collect::>() + .len(), + 0 + ); + scheduler.release_telecommands(|_, _| { + panic!("should not be called"); + }); + + // Release first TC. + scheduler.update_time(UnixTime::new(6, 0)); + assert_eq!( + scheduler + .telecommands_to_release() + .collect::>() + .len(), + 2 + ); + let mut index = 0; + scheduler.release_telecommands(|tc_id_scheduled, tc_raw| { + if index == 0 { + assert_eq!(tc_id_0, tc_id_scheduled.base); + assert_eq!(reader_0.checksum(), tc_id_scheduled.crc16); + assert_eq!(tc_raw, test_tc_0_raw); + } else { + assert_eq!(tc_id_1, tc_id_scheduled.base); + assert_eq!(reader_1.checksum(), tc_id_scheduled.crc16); + assert_eq!(tc_raw, test_tc_1_raw); + } + index += 1; + }); + assert_eq!( + scheduler + .telecommands_to_release() + .collect::>() + .len(), + 0 + ); + assert_eq!(scheduler.current_fill_count().packets, 0); + assert_eq!(scheduler.current_fill_count().bytes, 0); + assert_eq!(scheduler.num_of_entries(), 0); + } + #[test] fn test_packet_limit_reached() { let unix_time = UnixTime::new(0, 0); @@ -587,7 +668,7 @@ mod tests { Limits::new(Some(3), None), Duration::from_millis(1000), ); - let test_tc_0 = test_tc(&[42]); + let test_tc_0 = test_tc(&[42], u14::ZERO); let test_tc_0_raw = test_tc_0.to_vec(); let reader = CcsdsPacketReader::new(&test_tc_0_raw, Some(ChecksumType::WithCrc16)).unwrap(); let tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&test_tc_0); @@ -618,7 +699,7 @@ mod tests { #[test] fn test_byte_limit_reached() { let unix_time = UnixTime::new(0, 0); - let test_tc_0 = test_tc(&[42]); + let test_tc_0 = test_tc(&[42], u14::ZERO); let mut scheduler = CcsdsScheduler::new( unix_time, Limits::new(None, Some(test_tc_0.len_written() * 3)), @@ -659,7 +740,7 @@ mod tests { Limits::new(Some(100), Some(1024)), Duration::from_millis(1000), ); - let test_tc = test_tc(&[1, 2, 3]); + let test_tc = test_tc(&[1, 2, 3], u14::ZERO); let tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&test_tc); let test_tc_raw = test_tc.to_vec(); let reader = CcsdsPacketReader::new(&test_tc_raw, Some(ChecksumType::WithCrc16)).unwrap(); @@ -674,8 +755,93 @@ mod tests { } #[test] - fn test_deletion_by_window() { - //TODO + fn test_deletion_by_window_0() { + let unix_time = UnixTime::new(0, 0); + let mut scheduler = CcsdsScheduler::new( + unix_time, + Limits::new(Some(100), Some(1024)), + Duration::from_millis(1000), + ); + let test_tc_0 = test_tc(&[42], u14::ZERO); + let test_tc_1 = test_tc(&[1, 2, 3], u14::new(1)); + let test_tc_2 = test_tc(&[1, 2, 3], u14::new(2)); + let test_tc_0_raw = test_tc_0.to_vec(); + let test_tc_1_raw = test_tc_1.to_vec(); + let test_tc_2_raw = test_tc_2.to_vec(); + let reader_0 = + CcsdsPacketReader::new(&test_tc_0_raw, Some(ChecksumType::WithCrc16)).unwrap(); + let reader_1 = + CcsdsPacketReader::new(&test_tc_1_raw, Some(ChecksumType::WithCrc16)).unwrap(); + let reader_2 = + CcsdsPacketReader::new(&test_tc_2_raw, Some(ChecksumType::WithCrc16)).unwrap(); + scheduler + .insert_telecommand_with_reader(&reader_0, UnixTime::new(2, 0)) + .unwrap(); + scheduler + .insert_telecommand_with_reader(&reader_1, UnixTime::new(5, 0)) + .unwrap(); + scheduler + .insert_telecommand_with_reader(&reader_2, UnixTime::new(7, 0)) + .unwrap(); + let deleted = scheduler.delete_in_time_window(UnixTime::new(3, 0), UnixTime::new(6, 0)); + assert!(deleted); + assert_eq!(scheduler.current_fill_count().packets, 2); + assert_eq!( + scheduler.current_fill_count().bytes, + test_tc_0_raw.len() + test_tc_2_raw.len() + ); + scheduler.update_time(UnixTime::new(10, 0)); + let mut index = 0; + scheduler.release_telecommands(|_id, packet| { + if index == 0 { + assert_eq!(packet, test_tc_0_raw); + } else { + assert_eq!(packet, test_tc_2_raw); + } + index += 1; + }); + assert_eq!(scheduler.current_fill_count().packets, 0); + assert_eq!(scheduler.current_fill_count().bytes, 0); + } + + #[test] + fn test_deletion_by_window_1() { + let unix_time = UnixTime::new(0, 0); + let mut scheduler = CcsdsScheduler::new( + unix_time, + Limits::new(Some(100), Some(1024)), + Duration::from_millis(1000), + ); + let test_tc_0 = test_tc(&[42], u14::ZERO); + let test_tc_1 = test_tc(&[1, 2, 3], u14::new(1)); + let test_tc_2 = test_tc(&[1, 2, 3], u14::new(2)); + let test_tc_0_raw = test_tc_0.to_vec(); + let test_tc_1_raw = test_tc_1.to_vec(); + let test_tc_2_raw = test_tc_2.to_vec(); + let reader_0 = + CcsdsPacketReader::new(&test_tc_0_raw, Some(ChecksumType::WithCrc16)).unwrap(); + let reader_1 = + CcsdsPacketReader::new(&test_tc_1_raw, Some(ChecksumType::WithCrc16)).unwrap(); + let reader_2 = + CcsdsPacketReader::new(&test_tc_2_raw, Some(ChecksumType::WithCrc16)).unwrap(); + scheduler + .insert_telecommand_with_reader(&reader_0, UnixTime::new(2, 0)) + .unwrap(); + scheduler + .insert_telecommand_with_reader(&reader_1, UnixTime::new(5, 0)) + .unwrap(); + scheduler + .insert_telecommand_with_reader(&reader_2, UnixTime::new(7, 0)) + .unwrap(); + // This only deletes the first 2 TCs. + let deleted = scheduler.delete_in_time_window(UnixTime::new(2, 0), UnixTime::new(7, 0)); + assert!(deleted); + assert_eq!(scheduler.current_fill_count().packets, 1); + assert_eq!(scheduler.current_fill_count().bytes, test_tc_2_raw.len()); + scheduler.update_time(UnixTime::new(10, 0)); + scheduler.release_telecommands(|_id, packet| { + assert_eq!(packet, test_tc_2_raw); + }); } #[test]