use crate::data::error::EcState;
use crate::utils::ffi::{FsoeState, FsoeError};
pub fn state_description(state: EcState) -> &'static str {
match state {
EcState::None => "None",
EcState::Init => "Init",
EcState::PreOp => "PreOp",
EcState::Boot => "Boot",
EcState::SafeOp => "SafeOp",
EcState::Operational => "OP",
}
}
pub fn al_status_description(code: u16) -> &'static str {
match code {
0x0000 => "No error",
0x0001 => "Unspecified error",
0x0002 => "No memory",
0x0003 => "Invalid device setup",
0x0004 => "Invalid revision",
0x0006 => "SII/EEPROM information does not match firmware",
0x0007 => "Firmware update not successful",
0x000E => "License error",
0x0011 => "Invalid requested state change",
0x0012 => "Unknown requested state",
0x0013 => "Bootstrap not supported",
0x0014 => "No valid firmware",
0x0015 => "Invalid mailbox configuration",
0x0016 => "Invalid mailbox configuration",
0x0017 => "Invalid sync manager configuration",
0x0018 => "No valid inputs available",
0x0019 => "No valid outputs",
0x001A => "Synchronization error",
0x001B => "Sync manager watchdog",
0x001C => "Invalid sync manager types",
0x001D => "Invalid output configuration",
0x001E => "Invalid input configuration",
0x001F => "Invalid watchdog configuration",
0x0020 => "Slave needs cold start",
0x0021 => "Slave needs INIT",
0x0022 => "Slave needs PREOP",
0x0023 => "Slave needs SAFEOP",
0x0024 => "Invalid input mapping",
0x0025 => "Invalid output mapping",
0x0026 => "Inconsistent settings",
0x0027 => "Freerun not supported",
0x0028 => "Synchronisation not supported",
0x0029 => "Freerun needs 3buffer mode",
0x002A => "Background watchdog",
0x002B => "No valid Inputs and Outputs",
0x002C => "Fatal sync error",
0x002D => "No sync error",
0x002E => "Cycle time too small",
0x0030 => "Invalid DC SYNC configuration",
0x0031 => "Invalid DC latch configuration",
0x0032 => "PLL error",
0x0033 => "DC sync IO error",
0x0034 => "DC sync timeout error",
0x0035 => "DC invalid sync cycle time",
0x0036 => "DC invalid sync0 cycle time",
0x0037 => "DC invalid sync1 cycle time",
0x0041 => "MBX_AOE",
0x0042 => "MBX_EOE",
0x0043 => "MBX_COE",
0x0044 => "MBX_FOE",
0x0045 => "MBX_SOE",
0x004F => "MBX_VOE",
0x0050 => "EEPROM no access",
0x0051 => "EEPROM error",
0x0052 => "External hardware not ready",
0x0060 => "Slave restarted locally",
0x0061 => "Device identification value updated",
0x0070 => "Detected module ident list does not match",
0x0080 => "Supply voltage too low",
0x0081 => "Supply voltage too high",
0x0082 => "Temperature too low",
0x0083 => "Temperature too high",
0x00F0 => "Application controller available",
_ => "Unknown",
}
}
pub fn al_status_description_cn(code: u16) -> &'static str {
match code {
0x0000 => "无错误",
0x0001 => "未指定错误",
0x0002 => "内存不足",
0x0003 => "无效的设备设置",
0x0004 => "无效的修订版本",
0x0006 => "SII/EEPROM 信息与固件不匹配",
0x0007 => "固件更新失败",
0x000E => "许可证错误",
0x0011 => "无效的状态转换请求",
0x0012 => "未知的状态转换请求",
0x0013 => "引导模式不支持",
0x0014 => "无有效固件",
0x0015 => "无效的邮箱配置 (Boot 状态)",
0x0016 => "无效的邮箱配置 (PreOp 状态)",
0x0017 => "无效的同步管理器配置",
0x0018 => "无有效输入",
0x0019 => "无有效输出",
0x001A => "同步错误",
0x001B => "同步管理器看门狗",
0x001C => "无效的同步管理器类型",
0x001D => "无效的输出配置",
0x001E => "无效的输入配置",
0x001F => "无效的看门狗配置",
0x0020 => "从站需要冷启动",
0x0021 => "从站需要 INIT 状态",
0x0022 => "从站需要 PREOP 状态",
0x0023 => "从站需要 SAFEOP 状态",
0x0024 => "无效的输入映射",
0x0025 => "无效的输出映射",
0x0026 => "设置不一致",
0x0027 => "FreeRun 模式不支持",
0x0028 => "同步模式不支持",
0x0029 => "FreeRun 需要 3 缓冲区模式",
0x002A => "后台看门狗",
0x002B => "无有效的输入输出数据",
0x002C => "致命同步错误",
0x002D => "无同步错误",
0x002E => "周期时间过短",
0x0030 => "无效的 DC SYNC 配置",
0x0031 => "无效的 DC 锁存配置",
0x0032 => "PLL 锁定错误",
0x0033 => "DC IO 错误",
0x0034 => "DC 超时错误",
0x0035 => "DC 无效的同步周期长度",
0x0036 => "DC 无效的 Sync0 周期长度",
0x0037 => "DC 无效的 Sync1 周期长度",
0x0041 => "MBX_AOE 错误",
0x0042 => "MBX_EOE 错误",
0x0043 => "MBX_COE 错误",
0x0044 => "MBX_FOE 错误",
0x0045 => "MBX_SOE 错误",
0x004F => "MBX_VOE 错误",
0x0050 => "EEPROM 无访问权限",
0x0051 => "EEPROM 错误",
0x0052 => "外部硬件未就绪",
0x0060 => "从站重启",
0x0061 => "设备标识值已更新",
0x0070 => "检测到的模块标识列表不匹配",
0x0080 => "供电电压过低",
0x0081 => "供电电压过高",
0x0082 => "温度过低",
0x0083 => "温度过高",
0x00F0 => "应用控制器可用",
_ => {
if code >= 0x8000 {
"厂商特定错误"
} else {
"未知错误"
}
}
}
}
pub fn sdo_error_description(code: u32) -> &'static str {
match code {
0x00000000 => "No error",
0x05030000 => "Toggle bit not changed",
0x05040000 => "SDO protocol timeout",
0x05040001 => "Client/Server command specifier not valid or unknown",
0x05040005 => "Out of memory",
0x06010000 => "Unsupported access to an object",
0x06010001 => "Attempt to read to a write only object",
0x06010002 => "Attempt to write to a read only object",
0x06010003 => "Subindex can not be written, SI0 must be 0 for write access",
0x06010004 => "SDO Complete access not supported for variable length objects",
0x06010005 => "Object length exceeds mailbox size",
0x06010006 => "Object mapped to RxPDO, SDO download blocked",
0x06020000 => "The object does not exist in the object directory",
0x06040041 => "The object can not be mapped into the PDO",
0x06040042 => "The number and length of the objects to be mapped would exceed the PDO length",
0x06040043 => "General parameter incompatibility reason",
0x06040047 => "General internal incompatibility in the device",
0x06060000 => "Access failed due to a hardware error",
0x06070010 => "Data type does not match, length of service parameter does not match",
0x06070012 => "Data type does not match, length of service parameter too high",
0x06070013 => "Data type does not match, length of service parameter too low",
0x06090011 => "Subindex does not exist",
0x06090030 => "Value range of parameter exceeded (only for write access)",
0x06090031 => "Value of parameter written too high",
0x06090032 => "Value of parameter written too low",
0x06090033 => "Configured module list does not match detected module list",
0x06090036 => "Maximum value is less than minimum value",
0x08000000 => "General error",
0x08000020 => "Data cannot be transferred or stored to the application",
0x08000021 => "Data cannot be transferred or stored to the application because of local control",
0x08000022 => "Data cannot be transferred or stored to the application because of the present device state",
0x08000023 => "Object dictionary dynamic generation fails or no object dictionary is present",
_ => "Unknown",
}
}
pub fn soe_error_description(code: u16) -> &'static str {
match code {
0x0000 => "No error",
0x1001 => "No IDN",
0x1009 => "Invalid access to element 1",
0x2001 => "No Name",
0x2002 => "Name transmission too short",
0x2003 => "Name transmission too long",
0x2004 => "Name cannot be changed (read only)",
0x2005 => "Name is write-protected at this time",
0x3002 => "Attribute transmission too short",
0x3003 => "Attribute transmission too long",
0x3004 => "Attribute cannot be changed (read only)",
0x3005 => "Attribute is write-protected at this time",
0x4001 => "No units",
0x4002 => "Unit transmission too short",
0x4003 => "Unit transmission too long",
0x4004 => "Unit cannot be changed (read only)",
0x4005 => "Unit is write-protected at this time",
0x5001 => "No minimum input value",
0x5002 => "Minimum input value transmission too short",
0x5003 => "Minimum input value transmission too long",
0x5004 => "Minimum input value cannot be changed (read only)",
0x5005 => "Minimum input value is write-protected at this time",
0x6001 => "No maximum input value",
0x6002 => "Maximum input value transmission too short",
0x6003 => "Maximum input value transmission too long",
0x6004 => "Maximum input value cannot be changed (read only)",
0x6005 => "Maximum input value is write-protected at this time",
0x7002 => "Operation data transmission too short",
0x7003 => "Operation data transmission too long",
0x7004 => "Operation data cannot be changed (read only)",
0x7005 => "Operation data is write-protected at this time (state)",
0x7006 => "Operation data is smaller than the minimum input value",
0x7007 => "Operation data is smaller than the maximum input value",
0x7008 => "Invalid operation data: Configured IDN will not be supported",
0x7009 => "Operation data write protected by a password",
0x700A => "Operation data is write protected, it is configured cyclically",
0x700B => "Invalid indirect addressing",
0x700C => "Operation data is write protected, due to other settings",
0x7010 => "Procedure command already active",
0x7011 => "Procedure command not interruptible",
0x7012 => "Procedure command at this time not executable (state)",
0x7013 => "Procedure command not executable (invalid or false parameters)",
0x7014 => "No data state",
0x8001 => "No default value",
0x8002 => "Default value transmission too long",
0x8004 => "Default value cannot be changed, read only",
0x800A => "Invalid drive number",
0x800B => "General error",
0x800C => "No element addressed",
_ => "Unknown",
}
}
pub fn mailbox_error_description(code: u16) -> &'static str {
match code {
0x0000 => "No error",
0x0001 => "Syntax of 6 octet Mailbox Header is wrong",
0x0002 => "The mailbox protocol is not supported",
0x0003 => "Channel Field contains wrong value",
0x0004 => "The service is not supported",
0x0005 => "Invalid mailbox header",
0x0006 => "Length of received mailbox data is too short",
0x0007 => "No more memory in slave",
0x0008 => "The length of data is inconsistent",
_ => "Unknown",
}
}
pub fn mailbox_type_description(mbx_type: u16) -> &'static str {
match mbx_type {
0x00 => "Error type",
0x01 => "ADS over EtherCAT",
0x02 => "Ethernet over EtherCAT",
0x03 => "CANopen over EtherCAT",
0x04 => "File over EtherCAT",
0x05 => "Servo over EtherCAT",
0x0F => "Vendor over EtherCAT",
_ => "Unknown",
}
}
const ATYPE_RPRE: u16 = 0x01; const ATYPE_RSAFE: u16 = 0x02; const ATYPE_ROP: u16 = 0x04; const ATYPE_WPRE: u16 = 0x08; const ATYPE_WSAFE: u16 = 0x10; const ATYPE_WOP: u16 = 0x20;
pub fn obj_access_description(access: u16) -> String {
let mut s = String::with_capacity(6);
s.push(if access & ATYPE_RPRE != 0 { 'R' } else { '_' });
s.push(if access & ATYPE_WPRE != 0 { 'W' } else { '_' });
s.push(if access & ATYPE_RSAFE != 0 { 'R' } else { '_' });
s.push(if access & ATYPE_WSAFE != 0 { 'W' } else { '_' });
s.push(if access & ATYPE_ROP != 0 { 'R' } else { '_' });
s.push(if access & ATYPE_WOP != 0 { 'W' } else { '_' });
s
}
pub fn obj_access_description_cn(access: u16) -> String {
let can_read = (access & (ATYPE_RPRE | ATYPE_RSAFE | ATYPE_ROP)) != 0;
let can_write = (access & (ATYPE_WPRE | ATYPE_WSAFE | ATYPE_WOP)) != 0;
let mut writable_states = Vec::new();
if access & ATYPE_WPRE != 0 { writable_states.push("PreOP"); }
if access & ATYPE_WSAFE != 0 { writable_states.push("SafeOP"); }
if access & ATYPE_WOP != 0 { writable_states.push("OP"); }
if can_read && can_write {
format!("读写({}可写)", writable_states.join(","))
} else if can_read {
"只读".to_string()
} else if can_write {
format!("只写({}可写)", writable_states.join(","))
} else {
"无权限".to_string()
}
}
pub fn write_condition_description(access: u16) -> String {
let mut conditions = Vec::new();
if access & ATYPE_WPRE != 0 { conditions.push("PreOP"); }
if access & ATYPE_WSAFE != 0 { conditions.push("SafeOP"); }
if access & ATYPE_WOP != 0 { conditions.push("OP"); }
if conditions.is_empty() {
"不可写入".to_string()
} else {
format!("写入条件: {}", conditions.join("/"))
}
}
pub fn can_write_in_state(access: u16, state: EcState) -> bool {
match state {
EcState::PreOp => (access & ATYPE_WPRE) != 0,
EcState::SafeOp => (access & (ATYPE_WPRE | ATYPE_WSAFE)) != 0,
EcState::Operational => (access & (ATYPE_WPRE | ATYPE_WSAFE | ATYPE_WOP)) != 0,
_ => false,
}
}
pub fn data_type_short_name(dt: u16) -> &'static str {
match dt {
0x0001 => "bool",
0x0002 => "int8",
0x0003 => "int16",
0x0004 => "int32",
0x0005 => "uint8",
0x0006 => "uint16",
0x0007 => "uint32",
0x0008 => "float",
0x0009 => "string",
0x000A => "byte[]",
0x000B => "string",
0x000C => "datetime",
0x000D => "timespan",
0x000F => "byte[]",
0x0010 => "int24",
0x0011 => "double",
0x0015 => "int64",
0x0016 => "uint24",
0x001B => "uint64",
0x0030 => "bit1",
0x0031 => "bit2",
0x0032 => "bit3",
0x0033 => "bit4",
0x0034 => "bit5",
0x0035 => "bit6",
0x0036 => "bit7",
0x0037 => "bit8",
_ => "unknown",
}
}
pub fn al_status_full_description(code: u16) -> String {
format!("0x{:04X}: {} / {}", code, al_status_description(code), al_status_description_cn(code))
}
pub fn link_state_description(state: u8) -> &'static str {
match state {
0 => "断开 (Disconnected)",
1 => "已连接 (Connected)",
3 => "仅主端口 (Primary Only)",
4 => "仅副端口 (Secondary Only)",
_ => "未知 (Unknown)",
}
}
pub fn access_description_with_state(access: u16, state: EcState) -> String {
let can_read = match state {
EcState::PreOp => (access & 0x01) != 0,
EcState::SafeOp => (access & 0x02) != 0,
EcState::Operational => (access & 0x04) != 0,
_ => false,
};
let can_write = can_write_in_state(access, state);
let state_name = match state {
EcState::PreOp => "PreOP",
EcState::SafeOp => "SafeOP",
EcState::Operational => "OP",
_ => "N/A",
};
if can_read && can_write {
format!("{}: 可读写", state_name)
} else if can_read {
format!("{}: 只读", state_name)
} else if can_write {
format!("{}: 只写", state_name)
} else {
format!("{}: 不可访问", state_name)
}
}
pub fn cia402_state_description(state: u8) -> &'static str {
match state {
0 => "初始化中 (Not Ready to Switch On)",
1 => "驱动禁用 (Switch On Disabled)",
2 => "准备就绪 (Ready to Switch On)",
3 => "已开启 (Switched On)",
4 => "运行使能 (Operation Enabled)",
5 => "快速停止 (Quick Stop Active)",
6 => "故障反应中 (Fault Reaction Active)",
7 => "故障 (Fault)",
_ => "未知 (Unknown)",
}
}
pub fn cia402_mode_description(mode: i8) -> &'static str {
match mode {
1 => "轮廓位置 (PP)",
2 => "速度 (VL)",
3 => "轮廓速度 (PV)",
4 => "轮廓转矩 (PT)",
6 => "回零 (HM)",
7 => "插补位置 (IP)",
8 => "周期同步位置 (CSP)",
9 => "周期同步速度 (CSV)",
10 => "周期同步转矩 (CST)",
11 => "周期同步转矩加速度 (CSTCA)",
_ => "未知 (Unknown)",
}
}
pub fn fsoe_state_description(state: FsoeState) -> &'static str {
match state {
FsoeState::Reset => "复位 (Reset)",
FsoeState::Session => "会话 (Session)",
FsoeState::Connection => "连接 (Connection)",
FsoeState::Parameter => "参数 (Parameter)",
FsoeState::Data => "数据传输 (Data)",
FsoeState::Failsafe => "失效安全 (Failsafe)",
}
}
pub fn fsoe_error_description(error: FsoeError) -> &'static str {
match error {
FsoeError::None => "无错误",
FsoeError::WrongCommand => "错误的命令",
FsoeError::UnknownCommand => "未知命令",
FsoeError::WrongConnId => "连接 ID 不匹配",
FsoeError::Crc => "CRC 校验失败",
FsoeError::Watchdog => "看门狗超时",
FsoeError::WrongAddress => "错误的 FSoE 地址",
FsoeError::WrongData => "无效数据",
FsoeError::CommParamLength => "通信参数长度错误",
FsoeError::CommParam => "通信参数错误",
FsoeError::AppParamLength => "应用参数长度错误",
FsoeError::AppParam => "应用参数错误",
FsoeError::UnexpectedSession => "意外的会话命令",
FsoeError::FailsafeData => "收到失效安全数据",
FsoeError::NotInitialized => "FSoE 未初始化",
FsoeError::MaxConnections => "达到最大连接数",
FsoeError::InvalidState => "无效状态转换",
}
}
pub fn port_type_description(port_type: u8) -> &'static str {
match port_type {
0 => "未使用 (Not Used)",
1 => "MII",
2 => "EBUS",
3 => "EBUS+",
_ => "未知 (Unknown)",
}
}
pub fn topology_type_description(topo: u8) -> &'static str {
match topo {
0 => "无链接 (No Link)",
1 => "端点 (End Point)",
2 => "中间节点 (Line)",
3 => "分支点 (Fork)",
4 => "交叉点 (Cross)",
_ => "未知 (Unknown)",
}
}
pub fn pdi_type_description(pdi: u8) -> &'static str {
match pdi {
0x00 => "无PDI (Interface deactivated)",
0x01 => "4个数字输入",
0x02 => "4个数字输出",
0x03 => "2个数字输入 + 2个数字输出",
0x04 => "数字I/O",
0x05 => "SPI从站",
0x06 => "过载保护输出",
0x07 => "ESC同步管理器",
0x08 => "uC async. 16bit",
0x09 => "uC async. 8bit",
0x0A => "uC sync. 16bit",
0x0B => "uC sync. 8bit",
0x10 => "32个数字输入/输出",
0x11 => "24个数字输入 + 8个数字输出",
0x12 => "16个数字输入 + 16个数字输出",
0x13 => "8个数字输入 + 24个数字输出",
0x80 => "On-chip bus",
_ => "未知类型",
}
}
pub fn device_type_description(dtype: u16) -> &'static str {
match dtype {
0 => "未定义",
1 => "静态设备(无IO映射)",
2 => "输入设备(无邮箱)",
3 => "输出设备(无邮箱)",
4 => "输入设备(有邮箱)",
5 => "输出设备(有邮箱)",
6 => "输入输出设备(无邮箱)",
7 => "输入输出设备(有邮箱)",
_ => "未知设备类型",
}
}
pub fn sync_manager_type_description(sm: u8) -> &'static str {
match sm {
0 => "未使用",
1 => "邮箱输出 (MbxOut)",
2 => "邮箱输入 (MbxIn)",
3 => "过程数据输出 (RxPDO)",
4 => "过程数据输入 (TxPDO)",
_ => "未知",
}
}
pub fn fmmu_type_description(fmmu: u8) -> &'static str {
match fmmu {
0 => "未使用",
1 => "输出 (Logical->Physical)",
2 => "输入 (Physical->Logical)",
3 => "同步管理器状态",
_ => "未知",
}
}
pub fn coe_details_description(details: u8) -> String {
let mut parts = Vec::new();
if details & 0x01 != 0 { parts.push("SDO"); }
if details & 0x02 != 0 { parts.push("SDO Info"); }
if details & 0x04 != 0 { parts.push("PDO Assign"); }
if details & 0x08 != 0 { parts.push("PDO Config"); }
if details & 0x10 != 0 { parts.push("Startup"); }
if details & 0x20 != 0 { parts.push("Complete Access"); }
if parts.is_empty() {
"无".to_string()
} else {
parts.join(", ")
}
}
pub fn eoe_details_description(details: u8) -> String {
let mut parts = Vec::new();
if details & 0x01 != 0 { parts.push("发送帧"); }
if details & 0x02 != 0 { parts.push("接收帧"); }
if details & 0x04 != 0 { parts.push("设置IP"); }
if details & 0x08 != 0 { parts.push("获取IP"); }
if parts.is_empty() {
"无".to_string()
} else {
parts.join(", ")
}
}
pub fn data_type_name(dt: u16) -> &'static str {
match dt {
0x0001 => "Boolean",
0x0002 => "Integer8",
0x0003 => "Integer16",
0x0004 => "Integer32",
0x0005 => "Unsigned8",
0x0006 => "Unsigned16",
0x0007 => "Unsigned32",
0x0008 => "Real32",
0x0009 => "VisibleString",
0x000A => "OctetString",
0x000B => "UnicodeString",
0x000C => "TimeOfDay",
0x000D => "TimeDifference",
0x000F => "Domain",
0x0010 => "Integer24",
0x0011 => "Real64",
0x0012 => "Integer40",
0x0013 => "Integer48",
0x0014 => "Integer56",
0x0015 => "Integer64",
0x0016 => "Unsigned24",
0x0018 => "Unsigned40",
0x0019 => "Unsigned48",
0x001A => "Unsigned56",
0x001B => "Unsigned64",
0x0030 => "Bit1",
0x0031 => "Bit2",
0x0032 => "Bit3",
0x0033 => "Bit4",
0x0034 => "Bit5",
0x0035 => "Bit6",
0x0036 => "Bit7",
0x0037 => "Bit8",
_ => "Unknown",
}
}