use std::collections::VecDeque;
use std::sync::Mutex;
use std::time::SystemTime;
#[derive(Clone, Debug)]
pub struct EmergencyMessage {
pub error_code: u16,
pub error_register: u8,
pub data: [u8; 5],
pub slave_index: u16,
pub timestamp: SystemTime,
}
impl EmergencyMessage {
pub fn error_description(&self) -> &str {
match self.error_code >> 8 {
0x00 => "已复位/无错误",
0x10 => "通用错误",
0x20 => "电流错误",
0x21 => "设备输入侧电流错误",
0x22 => "设备内部电流错误",
0x23 => "设备输出侧电流错误",
0x30 => "电压错误",
0x31 => "主电源电压错误",
0x32 => "设备内部电压错误",
0x33 => "输出电压错误",
0x40 => "温度错误",
0x41 => "环境温度错误",
0x42 => "设备温度错误",
0x50 => "设备硬件错误",
0x60 => "设备软件错误",
0x61 => "内部软件错误",
0x62 => "用户软件错误",
0x63 => "数据集错误",
0x70 => "附加模块错误",
0x80 => "监控错误",
0x81 => "通信错误",
0x82 => "协议错误",
0x90 => "外部错误",
0xF0 => "附加功能错误",
0xFF => "设备特定错误",
_ => "未知错误类别",
}
}
}
impl std::fmt::Display for EmergencyMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"EMCY[从站{}] 0x{:04X} ({}) 寄存器=0x{:02X}",
self.slave_index, self.error_code,
self.error_description(), self.error_register
)
}
}
pub struct EmcyRecorder {
history: Mutex<VecDeque<EmergencyMessage>>,
max_size: usize,
}
const MAX_EMCY_HISTORY_SIZE: usize = 256;
impl EmcyRecorder {
pub fn new() -> Self {
Self {
history: Mutex::new(VecDeque::with_capacity(MAX_EMCY_HISTORY_SIZE)),
max_size: MAX_EMCY_HISTORY_SIZE,
}
}
pub fn record(
&self,
slave_index: u16,
error_code: u16,
error_reg: u16,
b1: u8,
w1: u16,
w2: u16,
) {
let msg = EmergencyMessage {
error_code,
error_register: (error_reg & 0xFF) as u8,
data: [
b1,
(w1 & 0xFF) as u8,
(w1 >> 8) as u8,
(w2 & 0xFF) as u8,
(w2 >> 8) as u8,
],
slave_index,
timestamp: SystemTime::now(),
};
if let Ok(mut history) = self.history.lock() {
if history.len() >= self.max_size {
history.pop_front();
}
history.push_back(msg);
}
}
pub fn history(&self) -> Vec<EmergencyMessage> {
self.history
.lock()
.map(|h| h.iter().cloned().collect())
.unwrap_or_default()
}
pub fn clear_history(&self) {
if let Ok(mut history) = self.history.lock() {
history.clear();
}
}
pub fn count(&self) -> usize {
self.history.lock().map(|h| h.len()).unwrap_or(0)
}
}
impl Default for EmcyRecorder {
fn default() -> Self {
Self::new()
}
}