#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RealTimeError {
DeadlineMissed {
expected_cycles: u32,
actual_cycles: u32,
},
ExecutionTimeExceeded {
budget_cycles: u32,
used_cycles: u32,
},
JitterExceeded {
max_jitter: u32,
actual_jitter: u32,
},
PriorityInversion {
high_priority_task: u8,
blocking_task: u8,
},
InterruptLatencyExceeded {
max_latency: u32,
actual_latency: u32,
},
ContextSwitchOverhead {
expected_overhead: u32,
actual_overhead: u32,
},
WatchdogTimeout,
SchedulerOverrun,
TimerResolutionInsufficient,
ClockDrift {
expected_freq: u32,
actual_freq: u32,
},
ResourceContentionTimeout,
SynchronizationTimeout,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum RealTimePriority {
Background = 0,
Low = 1,
Normal = 2,
High = 3,
Critical = 4,
Interrupt = 5,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SchedulingPolicy {
RateMonotonic,
EarliestDeadlineFirst,
FixedPriorityPreemptive,
RoundRobin,
Custom,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TaskCharacteristics {
pub priority: RealTimePriority,
pub period_cycles: u32,
pub wcet_cycles: u32,
pub deadline_cycles: u32,
pub jitter_tolerance: u32,
}
impl TaskCharacteristics {
pub const fn new(
priority: RealTimePriority,
period_cycles: u32,
wcet_cycles: u32,
deadline_cycles: u32,
jitter_tolerance: u32,
) -> Self {
Self {
priority,
period_cycles,
wcet_cycles,
deadline_cycles,
jitter_tolerance,
}
}
pub const fn utilization(&self) -> f32 {
self.wcet_cycles as f32 / self.period_cycles as f32
}
pub const fn is_rm_schedulable(&self) -> bool {
self.deadline_cycles >= self.wcet_cycles && self.deadline_cycles <= self.period_cycles
}
pub const fn meets_deadline(&self, execution_time: u32) -> bool {
execution_time <= self.deadline_cycles
}
pub const fn jitter_acceptable(&self, jitter: u32) -> bool {
jitter <= self.jitter_tolerance
}
}
impl RealTimeError {
pub const fn is_critical(&self) -> bool {
match self {
Self::DeadlineMissed { .. }
| Self::PriorityInversion { .. }
| Self::WatchdogTimeout
| Self::SchedulerOverrun => true,
_ => false,
}
}
pub const fn is_recoverable(&self) -> bool {
match self {
Self::WatchdogTimeout | Self::SchedulerOverrun => false,
Self::DeadlineMissed { .. }
| Self::ExecutionTimeExceeded { .. }
| Self::JitterExceeded { .. }
| Self::PriorityInversion { .. }
| Self::InterruptLatencyExceeded { .. }
| Self::ContextSwitchOverhead { .. }
| Self::TimerResolutionInsufficient
| Self::ClockDrift { .. }
| Self::ResourceContentionTimeout
| Self::SynchronizationTimeout => true,
}
}
pub const fn category(&self) -> &'static str {
match self {
Self::DeadlineMissed { .. }
| Self::ExecutionTimeExceeded { .. }
| Self::JitterExceeded { .. } => "Timing",
Self::PriorityInversion { .. } | Self::SchedulerOverrun => "Scheduling",
Self::InterruptLatencyExceeded { .. } | Self::ContextSwitchOverhead { .. } => "System",
Self::WatchdogTimeout => "Safety",
Self::TimerResolutionInsufficient | Self::ClockDrift { .. } => "Clock",
Self::ResourceContentionTimeout | Self::SynchronizationTimeout => "Synchronization",
}
}
pub const fn severity(&self) -> u8 {
match self {
Self::WatchdogTimeout | Self::SchedulerOverrun => 4,
Self::DeadlineMissed { .. } | Self::PriorityInversion { .. } => 3,
Self::ExecutionTimeExceeded { .. }
| Self::InterruptLatencyExceeded { .. }
| Self::JitterExceeded { .. } => 2,
Self::ContextSwitchOverhead { .. }
| Self::TimerResolutionInsufficient
| Self::ClockDrift { .. }
| Self::ResourceContentionTimeout
| Self::SynchronizationTimeout => 1,
}
}
}
impl RealTimePriority {
pub const fn numeric_value(&self) -> u8 {
*self as u8
}
pub const fn is_higher_than(&self, other: &Self) -> bool {
self.numeric_value() > other.numeric_value()
}
pub const fn can_preempt(&self, other: &Self) -> bool {
self.is_higher_than(other)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_task_characteristics() {
let task = TaskCharacteristics::new(
RealTimePriority::High,
1000, 300, 800, 50, );
assert_eq!(task.utilization(), 0.3);
assert!(task.is_rm_schedulable());
assert!(task.meets_deadline(300));
assert!(!task.meets_deadline(900));
assert!(task.jitter_acceptable(30));
assert!(!task.jitter_acceptable(60));
}
#[test]
fn test_priority_ordering() {
assert!(RealTimePriority::Critical > RealTimePriority::High);
assert!(RealTimePriority::High > RealTimePriority::Normal);
assert!(RealTimePriority::Normal > RealTimePriority::Low);
assert!(RealTimePriority::Low > RealTimePriority::Background);
assert!(RealTimePriority::Critical.is_higher_than(&RealTimePriority::High));
assert!(RealTimePriority::Critical.can_preempt(&RealTimePriority::Normal));
}
#[test]
fn test_error_classification() {
let deadline_error = RealTimeError::DeadlineMissed {
expected_cycles: 1000,
actual_cycles: 1200,
};
let watchdog_error = RealTimeError::WatchdogTimeout;
assert!(deadline_error.is_critical());
assert!(deadline_error.is_recoverable());
assert_eq!(deadline_error.category(), "Timing");
assert_eq!(deadline_error.severity(), 3);
assert!(watchdog_error.is_critical());
assert!(!watchdog_error.is_recoverable());
assert_eq!(watchdog_error.category(), "Safety");
assert_eq!(watchdog_error.severity(), 4);
}
#[test]
fn test_error_categories() {
assert_eq!(
RealTimeError::DeadlineMissed {
expected_cycles: 100,
actual_cycles: 150
}
.category(),
"Timing"
);
assert_eq!(
RealTimeError::PriorityInversion {
high_priority_task: 1,
blocking_task: 2
}
.category(),
"Scheduling"
);
assert_eq!(
RealTimeError::InterruptLatencyExceeded {
max_latency: 50,
actual_latency: 75
}
.category(),
"System"
);
assert_eq!(RealTimeError::WatchdogTimeout.category(), "Safety");
assert_eq!(
RealTimeError::ClockDrift {
expected_freq: 1000,
actual_freq: 1010
}
.category(),
"Clock"
);
assert_eq!(
RealTimeError::SynchronizationTimeout.category(),
"Synchronization"
);
}
#[test]
fn test_severity_levels() {
assert_eq!(RealTimeError::WatchdogTimeout.severity(), 4);
assert_eq!(
RealTimeError::DeadlineMissed {
expected_cycles: 100,
actual_cycles: 150
}
.severity(),
3
);
assert_eq!(
RealTimeError::ExecutionTimeExceeded {
budget_cycles: 100,
used_cycles: 150
}
.severity(),
2
);
assert_eq!(
RealTimeError::ClockDrift {
expected_freq: 1000,
actual_freq: 1010
}
.severity(),
1
);
}
}