///|
/// Health levels for a monitored CAN channel.
pub enum BusHealthState {
Healthy
Busy
Degraded
Overloaded
Silent
} derive(Debug)
///|
/// A deterministic health assessment for dashboards and CI.
pub struct BusHealth {
state : BusHealthState
utilization : Double
drop_rate : Double
error_rate : Double
recommendations : Array[String]
}
///|
/// Assess health from frame metrics and virtual-bus counters.
pub fn assess_bus_health(
metrics : FrameMetrics,
dropped : Int,
duration_us : UInt64,
bitrate_kbps : UInt,
) -> BusHealth {
let utilization = bus_utilization(metrics, duration_us, bitrate_kbps)
let total = metrics.total()
let drop_rate = if total == 0 {
0.0
} else {
dropped.to_double() / total.to_double()
}
let error_rate = if total == 0 {
0.0
} else {
metrics.errors().to_double() / total.to_double()
}
let recommendations : Array[String] = []
let state = if total == 0 {
Silent
} else if drop_rate > 0.05 || utilization > 1.0 {
recommendations.push("reduce load or increase receive capacity")
Overloaded
} else if error_rate > 0.01 {
recommendations.push("inspect error frames and physical layer")
Degraded
} else if utilization > 0.7 {
recommendations.push("monitor arbitration latency")
Busy
} else {
Healthy
}
{ state, utilization, drop_rate, error_rate, recommendations }
}
///|
pub fn BusHealth::state(self : BusHealth) -> BusHealthState {
self.state
}
///|
pub fn BusHealth::utilization(self : BusHealth) -> Double {
self.utilization
}
///|
pub fn BusHealth::drop_rate(self : BusHealth) -> Double {
self.drop_rate
}
///|
pub fn BusHealth::error_rate(self : BusHealth) -> Double {
self.error_rate
}
///|
pub fn BusHealth::recommendations(self : BusHealth) -> Array[String] {
self.recommendations.copy()
}
///|
pub fn bus_health_name(state : BusHealthState) -> String {
match state {
Healthy => "healthy"
Busy => "busy"
Degraded => "degraded"
Overloaded => "overloaded"
Silent => "silent"
}
}
///|
pub fn BusHealth::to_text(self : BusHealth) -> String {
"state=\{bus_health_name(self.state)} utilization=\{self.utilization} drop_rate=\{self.drop_rate} error_rate=\{self.error_rate}"
}