darra-ethercat-master 2.0.1

商业 EtherCAT 主站协议栈 · 实时内核驱动 · 抖动 1µs · Windows + Linux · 多编程语言 · 全协议 · 支持复杂拓扑 + 热插拔 · ethercat.darra.xyz · Commercial EtherCAT Master protocol stack · Real-time kernel driver · 1µs jitter · Multi-platform · Multi-language · Complex topology + hot-plug.
//! CoE EMCY 紧急消息历史
//!
//! 对应 C# Slave/CoE_Emcy.cs
//! 将 EMCY 功能封装到 CoE 实例中。

use crate::utils::ffi;

/// 高层紧急消息 (CiA 301)
///
/// 与 C# `EmergencyMessage` / Java `CoE.EmergencyMessage` /
/// Python `EmergencyMessage` / CPP `EmergencyMessage` 字段对齐.
/// 由 [`From<&ffi::EmcyRecord>`] 实现把 DLL 原生记录转换得到.
#[derive(Debug, Clone, Copy)]
pub struct EmergencyMessage {
    /// 紧急错误代码 (CiA 301 Table 24)
    pub error_code: u16,
    /// 错误寄存器 (对象 0x1001)
    pub error_register: u8,
    /// 厂商特定数据 (5 字节)
    pub data: [u8; 5],
    /// 来源从站编号
    pub slave_index: u16,
    /// 接收时间戳 (毫秒, Unix epoch). 0 = 未设置.
    pub timestamp_ms: u64,
}

impl Default for EmergencyMessage {
    fn default() -> Self {
        Self {
            error_code: 0,
            error_register: 0,
            data: [0; 5],
            slave_index: 0,
            timestamp_ms: 0,
        }
    }
}

impl From<&ffi::EmcyRecord> for EmergencyMessage {
    fn from(r: &ffi::EmcyRecord) -> Self {
        // packed 字段需要 read_unaligned
        let error_code = unsafe { std::ptr::addr_of!(r.error_code).read_unaligned() };
        let error_register = unsafe { std::ptr::addr_of!(r.error_register).read_unaligned() };
        let data = unsafe { std::ptr::addr_of!(r.data).read_unaligned() };
        let slave_index = unsafe { std::ptr::addr_of!(r.slave_index).read_unaligned() };
        let ts = unsafe { std::ptr::addr_of!(r.timestamp_ms).read_unaligned() };
        Self {
            error_code,
            error_register,
            data,
            slave_index,
            timestamp_ms: ts as u64,
        }
    }
}

/// 从 DLL 获取 EMCY 历史记录
///
/// 对应 C# EmcyGetHistory
pub fn emcy_get_history(
    master_index: u16,
    slave_index: u16,
    max_records: usize,
) -> Vec<crate::utils::ffi::EmcyRecord> {
    let mut records = vec![crate::utils::ffi::EmcyRecord::default(); max_records];
    let count = unsafe {
        ffi::EmcyGetHistory(
            master_index,
            slave_index,
            records.as_mut_ptr(),
            max_records as i32,
        )
    };
    if count > 0 {
        records.truncate(count as usize);
    } else {
        records.clear();
    }
    records
}

/// 清除 EMCY 历史记录
///
/// 对应 C# EmcyClearHistory
pub fn emcy_clear_history(master_index: u16, slave_index: u16) {
    unsafe { ffi::EmcyClearHistory(master_index, slave_index); }
}

/// 获取 EMCY 记录数量
///
/// 对应 C# EmcyGetCount
pub fn emcy_get_count(master_index: u16, slave_index: u16) -> i32 {
    unsafe { ffi::EmcyGetCount(master_index, slave_index) }
}