use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use super::deadline::Deadline;
use super::path::PathWcet;
use super::wcet::WcetConfig;
use crate::testing::specs::csp::Event;
use crate::utils::jitter::JitterCalculator;
#[cfg(feature = "testing-timing")]
use crate::testing::schedulability::{SchedulabilityError, SchedulerType, Task, TaskSet};
#[derive(Debug, Clone)]
pub enum TimingConstraint {
Wcet(WcetConfig),
Deadline(Deadline),
Jitter(Duration, Option<Arc<dyn JitterCalculator>>),
}
#[derive(Debug, Default, Clone)]
pub struct TimingConstraints {
pub(crate) constraints: HashMap<Event, TimingConstraint>,
deadlines: Vec<Deadline>,
path_wcets: Vec<PathWcet>,
}
impl TimingConstraints {
pub fn add(&mut self, event: Event, constraint: TimingConstraint) {
if !matches!(constraint, TimingConstraint::Deadline(_)) {
self.constraints.insert(event, constraint);
}
}
pub fn add_deadline(&mut self, deadline: Deadline) {
self.deadlines.push(deadline);
}
pub fn get(&self, event: &Event) -> Option<&TimingConstraint> {
self.constraints.get(event)
}
pub fn has_constraint(&self, event: &Event) -> bool {
self.constraints.contains_key(event)
}
pub fn constrained_events_iter(&self) -> impl Iterator<Item = &Event> {
self.constraints.keys()
}
pub fn deadlines(&self) -> &[Deadline] {
&self.deadlines
}
pub fn add_path_wcet(&mut self, path_wcet: PathWcet) {
self.path_wcets.push(path_wcet);
}
pub fn path_wcets(&self) -> &[PathWcet] {
&self.path_wcets
}
#[cfg(feature = "testing-timing")]
pub fn to_task_set(
&self,
periods: &HashMap<Event, Duration>,
scheduler: SchedulerType,
) -> Result<TaskSet, SchedulabilityError> {
let mut tasks = Vec::new();
for (event, constraint) in &self.constraints {
if let TimingConstraint::Wcet(wcet_config) = constraint {
let period = periods
.get(event)
.ok_or_else(|| SchedulabilityError::MissingPeriod(event.0.to_string()))?;
let deadline = self
.deadlines
.iter()
.find(|d| &d.start_event == event || &d.end_event == event)
.map(|d| d.duration)
.unwrap_or(*period);
let priority = if matches!(scheduler, SchedulerType::RateMonotonic) {
Some(period.as_nanos() as u32) } else {
None
};
tasks.push(Task {
id: event.0.to_string(),
period: *period,
deadline,
wcet: wcet_config.duration,
priority,
});
}
}
Ok(TaskSet { tasks, scheduler })
}
}