darra-ethercat-master 1.99.7

商业 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.
Documentation
//! 辅助工具函数
//!
//! 对应 C# Utils/Help.cs
//! 提供字节数组到字符串的安全转换,支持多编码自动检测。

use encoding_rs::*;

/// 将字节数组转换为字符串 (自动检测编码)
///
/// 对应 C# Help.ConvertByteArrayToString
/// 尝试顺序: UTF-8 → GBK → GB2312 → UTF-16LE → ASCII
pub fn convert_byte_array_to_string(data: &[u8]) -> String {
    if data.is_empty() {
        return String::new();
    }

    // 1. 查找 null 终止符
    let effective = match data.iter().position(|&b| b == 0) {
        Some(pos) => &data[..pos],
        None => data,
    };

    if effective.is_empty() {
        return String::new();
    }

    // 2. 尝试 UTF-8
    if let Ok(s) = std::str::from_utf8(effective) {
        let trimmed = s.trim_matches(|c: char| c.is_control() && c != ' ');
        if !trimmed.is_empty() && trimmed.chars().all(|c| !c.is_control() || c == ' ') {
            return trimmed.to_string();
        }
    }

    // 3. 尝试 GBK (包含 GB2312)
    let (decoded, _, had_errors) = GBK.decode(effective);
    if !had_errors {
        let trimmed = decoded.trim_matches(|c: char| c.is_control() && c != ' ');
        if !trimmed.is_empty() {
            return trimmed.to_string();
        }
    }

    // 4. 尝试 UTF-16LE (如果长度是偶数)
    if effective.len() >= 2 && effective.len() % 2 == 0 {
        let (decoded, _, had_errors) = UTF_16LE.decode(effective);
        if !had_errors {
            let trimmed = decoded.trim_matches(|c: char| c.is_control() && c != ' ');
            if !trimmed.is_empty()
                && trimmed
                    .chars()
                    .all(|c| c.is_ascii_graphic() || c.is_alphanumeric() || c == ' ')
            {
                return trimmed.to_string();
            }
        }
    }

    // 5. ASCII 回退 (仅保留可打印字符)
    let ascii: String = effective
        .iter()
        .filter(|&&b| b >= 0x20 && b <= 0x7E)
        .map(|&b| b as char)
        .collect();
    ascii
}

/// 将固定长度字节数组转换为字符串
///
/// 对应 C# Help.ConvertByteArrayToString(FixedName)
pub fn convert_fixed_name_to_string(bytes: &[u8; 41]) -> String {
    convert_byte_array_to_string(bytes)
}

/// 格式化字节数组为十六进制显示字符串 (大写, 空格分隔)
///
/// 例如: [0x01, 0xAB, 0xFF] → "01 AB FF"
/// 注意: xml 模块中的 bytes_to_hex_string 是紧凑格式 (小写, 无分隔)
pub fn bytes_to_hex_display(data: &[u8]) -> String {
    data.iter()
        .map(|b| format!("{:02X}", b))
        .collect::<Vec<_>>()
        .join(" ")
}

/// 格式化 IP 地址
///
/// 例如: [192, 168, 1, 1] → "192.168.1.1"
pub fn ip_to_string(ip: &[u8; 4]) -> String {
    format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3])
}