diff --git a/satrs/src/ccsds/scheduler.rs b/satrs/src/ccsds/scheduler.rs index 9ec5a2c..5cfbb6d 100644 --- a/satrs/src/ccsds/scheduler.rs +++ b/satrs/src/ccsds/scheduler.rs @@ -135,7 +135,6 @@ pub mod alloc_mod { limits: Limits, pub(crate) current_time: UnixTime, time_margin: Duration, - enabled: bool, } impl CcsdsScheduler { @@ -146,7 +145,6 @@ pub mod alloc_mod { limits, current_time, time_margin, - enabled: true, } } @@ -179,18 +177,6 @@ pub mod alloc_mod { self.current_fill_count().packets } - /// Enable the scheduler. - #[inline] - pub fn enable(&mut self) { - self.enabled = true; - } - - /// Disable the scheduler. - #[inline] - pub fn disable(&mut self) { - self.enabled = false; - } - /// Update the current time. #[inline] pub fn update_time(&mut self, current_time: UnixTime) { @@ -271,14 +257,14 @@ pub mod alloc_mod { } /// Release all telecommands which should be released based on the current time. - pub fn release_telecommands( + pub fn release_telecommands( &mut self, mut releaser: R, ) { let tcs_to_release = self.telecommands_to_release(); for tc_group in tcs_to_release { for (packet_id, raw_tc) in tc_group.1 { - releaser(self.enabled, packet_id, raw_tc); + releaser(packet_id, raw_tc); } } self.tc_map.retain(|k, _| k > &self.current_time); @@ -295,6 +281,55 @@ pub mod alloc_mod { self.tc_map.range(..=self.current_time) } + /// Delete scheduled telecommand by their packet ID. + /// + /// Returns whether any telecommand was deleted. This function might have to be called + /// multiple times if multiple identical CCSDS packet IDs are possible. + pub fn delete_by_id(&mut self, packet_id: &CcsdsSchedulePacketId) -> bool { + let mut was_removed = false; + self.tc_map.retain(|_, v| { + let len_before = v.len(); + v.retain(|(stored_id, _)| stored_id != packet_id); + let has_remaining = !v.is_empty(); + if v.len() < len_before { + was_removed = true; + } + has_remaining + }); + was_removed + } + + /// 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 { + let len_before = self.tc_map.len(); + 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. + /// + /// Returns whether any telecommands were deleted. + pub fn delete_from_start(&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. + /// + /// Returns whether any telecommands were deleted. + pub fn delete_until_end(&mut self, end_time: UnixTime) -> bool { + let len_before = self.tc_map.len(); + self.tc_map.retain(|k, _| k > &end_time); + self.tc_map.len() < len_before + } + /// Completely clear the scheduler. pub fn clear(&mut self) { self.tc_map.clear(); @@ -340,11 +375,26 @@ mod tests { 0 ); assert_eq!(scheduler.current_time(), &unix_time); - scheduler.release_telecommands(|_, _, _| { + scheduler.release_telecommands(|_, _| { panic!("should not be called"); }); } + #[test] + fn test_mutable_closure() { + let unix_time = UnixTime::new(0, 0); + let mut scheduler = CcsdsScheduler::new( + unix_time, + Limits::new(Some(100), Some(1024)), + Duration::from_millis(5000), + ); + let mut some_flag = false; + // We should be able to manipulate the boolean inside the closure. + scheduler.release_telecommands(|_, _| { + some_flag = true; + }); + } + #[test] fn test_clear() { let unix_time = UnixTime::new(0, 0); @@ -408,7 +458,7 @@ mod tests { .len(), 0 ); - scheduler.release_telecommands(|_, _, _| { + scheduler.release_telecommands(|_, _| { panic!("should not be called"); }); scheduler.update_time(UnixTime::new(3, 0)); @@ -419,8 +469,7 @@ mod tests { .len(), 1 ); - scheduler.release_telecommands(|enabled, tc_id_scheduled, tc_raw| { - assert!(enabled); + scheduler.release_telecommands(|tc_id_scheduled, tc_raw| { assert_eq!(tc_id, tc_id_scheduled.base); assert_eq!(checksum, tc_id_scheduled.crc16); assert_eq!(tc_raw, test_tc_raw); @@ -475,7 +524,7 @@ mod tests { .len(), 0 ); - scheduler.release_telecommands(|_, _, _| { + scheduler.release_telecommands(|_, _| { panic!("should not be called"); }); @@ -488,8 +537,7 @@ mod tests { .len(), 1 ); - scheduler.release_telecommands(|enabled, tc_id_scheduled, tc_raw| { - assert!(enabled); + scheduler.release_telecommands(|tc_id_scheduled, tc_raw| { 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); @@ -514,8 +562,7 @@ mod tests { .len(), 1 ); - scheduler.release_telecommands(|enabled, tc_id_scheduled, tc_raw| { - assert!(enabled); + scheduler.release_telecommands(|tc_id_scheduled, tc_raw| { 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); @@ -603,4 +650,41 @@ mod tests { Err(ScheduleError::ByteLimitReached) ); } + + #[test] + fn test_deletion_by_id() { + 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 = test_tc(&[1, 2, 3]); + 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(); + let checksum = reader.checksum(); + let id = CcsdsSchedulePacketId::new(tc_id, checksum); + scheduler + .insert_telecommand_with_reader(&reader, UnixTime::new(2, 0)) + .unwrap(); + scheduler.delete_by_id(&id); + assert_eq!(scheduler.current_fill_count().packets, 0); + assert_eq!(scheduler.current_fill_count().bytes, 0); + } + + #[test] + fn test_deletion_by_window() { + //TODO + } + + #[test] + fn test_deletion_from_start() { + //TODO + } + + #[test] + fn test_deletion_until_end() { + //TODO + } }