use std::fmt;
#[derive(Debug, Clone)]
pub enum DarraError {
AlreadyInitialized,
NotInitialized,
Timeout,
NoSlaves,
NetworkFailed(i32),
StateChangeFailed(u8),
SdoReadFailed { index: u16, subindex: u8, abort_code: Option<crate::data::types::SDOError> },
SdoWriteFailed { index: u16, subindex: u8, abort_code: Option<crate::data::types::SDOError> },
SoeFailed(u16),
FoeFailed(String),
EoeFailed,
AoeFailed,
VoeFailed,
InvalidParameter(String),
ConfigLoadFailed(i32),
NullPointer,
CiA402Failed(String),
EmcyFailed,
PdoFailed(String),
TopologyFailed,
RedundancyFailed,
RegisterFailed,
DiagnosticsFailed,
WdkFailed(String),
UdpFailed,
Other(String),
}
impl fmt::Display for DarraError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::AlreadyInitialized => write!(f, "主站已初始化"),
Self::NotInitialized => write!(f, "主站未初始化"),
Self::Timeout => write!(f, "操作超时"),
Self::NoSlaves => write!(f, "未发现从站"),
Self::NetworkFailed(code) => write!(f, "网络配置失败 (返回码: {})", code),
Self::StateChangeFailed(state) => write!(f, "状态切换失败 (目标: 0x{:02X})", state),
Self::SdoReadFailed { index, subindex, abort_code } => {
match abort_code {
Some(ac) => write!(f, "SDO 读取失败 (0x{:04X}:{:02X}, abort=0x{:08X})", index, subindex, *ac as u32),
None => write!(f, "SDO 读取失败 (0x{:04X}:{:02X})", index, subindex),
}
}
Self::SdoWriteFailed { index, subindex, abort_code } => {
match abort_code {
Some(ac) => write!(f, "SDO 写入失败 (0x{:04X}:{:02X}, abort=0x{:08X})", index, subindex, *ac as u32),
None => write!(f, "SDO 写入失败 (0x{:04X}:{:02X})", index, subindex),
}
}
Self::SoeFailed(idn) => write!(f, "SoE 操作失败 (IDN: 0x{:04X})", idn),
Self::FoeFailed(name) => write!(f, "FoE 操作失败 (文件: {})", name),
Self::EoeFailed => write!(f, "EoE 操作失败"),
Self::AoeFailed => write!(f, "AoE 操作失败"),
Self::VoeFailed => write!(f, "VoE 操作失败"),
Self::InvalidParameter(msg) => write!(f, "无效参数: {}", msg),
Self::ConfigLoadFailed(code) => write!(f, "配置加载失败 (返回码: {})", code),
Self::NullPointer => write!(f, "DLL 返回空指针"),
Self::CiA402Failed(msg) => write!(f, "CiA 402 操作失败: {}", msg),
Self::EmcyFailed => write!(f, "EMCY 操作失败"),
Self::PdoFailed(msg) => write!(f, "PDO 操作失败: {}", msg),
Self::TopologyFailed => write!(f, "拓扑操作失败"),
Self::RedundancyFailed => write!(f, "冗余操作失败"),
Self::RegisterFailed => write!(f, "寄存器操作失败"),
Self::DiagnosticsFailed => write!(f, "诊断操作失败"),
Self::WdkFailed(msg) => write!(f, "WDK 操作失败: {}", msg),
Self::UdpFailed => write!(f, "UDP 操作失败"),
Self::Other(msg) => write!(f, "{}", msg),
}
}
}
impl std::error::Error for DarraError {}
pub type Result<T> = std::result::Result<T, DarraError>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum EcState {
None = 0x00,
Init = 0x01,
PreOp = 0x02,
Boot = 0x03,
SafeOp = 0x04,
Operational = 0x08,
}
impl EcState {
pub fn from_raw(val: u8) -> Option<Self> {
match val & 0x0F {
0x00 => Some(Self::None),
0x01 => Some(Self::Init),
0x02 => Some(Self::PreOp),
0x03 => Some(Self::Boot),
0x04 => Some(Self::SafeOp),
0x08 => Some(Self::Operational),
_ => None,
}
}
pub fn has_error(raw: u8) -> bool {
(raw & 0x10) != 0
}
pub fn format(raw: u8) -> String {
let base = match raw & 0x0F {
0x00 => "None",
0x01 => "Init",
0x02 => "PreOp",
0x03 => "Boot",
0x04 => "SafeOp",
0x08 => "OP",
_ => "Unknown",
};
if (raw & 0x10) != 0 {
format!("{}+Error", base)
} else {
base.to_string()
}
}
}
impl fmt::Display for EcState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self {
Self::None => "None",
Self::Init => "Init",
Self::PreOp => "PreOp",
Self::Boot => "Boot",
Self::SafeOp => "SafeOp",
Self::Operational => "OP",
};
write!(f, "{}", name)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum CiA402State {
NotReady = 0,
SwitchOnDisabled = 1,
ReadyToSwitchOn = 2,
SwitchedOn = 3,
OperationEnabled = 4,
QuickStopActive = 5,
FaultReaction = 6,
Fault = 7,
Unknown = 99,
}
impl CiA402State {
pub fn from_raw(val: i32) -> Self {
match val {
0 => Self::NotReady,
1 => Self::SwitchOnDisabled,
2 => Self::ReadyToSwitchOn,
3 => Self::SwitchedOn,
4 => Self::OperationEnabled,
5 => Self::QuickStopActive,
6 => Self::FaultReaction,
7 => Self::Fault,
_ => Self::Unknown,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i8)]
pub enum CiA402Mode {
PP = 1,
VL = 2,
PV = 3,
PT = 4,
HM = 6,
IP = 7,
CSP = 8,
CSV = 9,
CST = 10,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum LinkState {
Disconnected = 0,
Connected = 1,
Redundancy = 2,
PrimaryOnly = 3,
SecondaryOnly = 4,
}
impl LinkState {
pub fn from_raw(val: u8) -> Self {
match val {
0 => Self::Disconnected,
1 => Self::Connected,
2 => Self::Redundancy,
3 => Self::PrimaryOnly,
4 => Self::SecondaryOnly,
_ => Self::Disconnected,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum RedundancyState {
None = 0,
Primary = 1,
Secondary = 2,
Both = 3,
}
impl RedundancyState {
pub fn from_raw(val: i32) -> Self {
match val {
0 => Self::None,
1 => Self::Primary,
2 => Self::Secondary,
3 => Self::Both,
_ => Self::None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum FoEErrorCode {
NotDefined = 0x8000,
NotFound = 0x8001,
AccessDenied = 0x8002,
DiskFull = 0x8003,
Illegal = 0x8004,
PacketNumberWrong = 0x8005,
AlreadyExists = 0x8006,
NoUser = 0x8007,
BootstrapOnly = 0x8008,
NotBootstrap = 0x8009,
NoRights = 0x800A,
ProgramError = 0x800B,
}
impl FoEErrorCode {
pub fn from_dll_error(dll_error_code: i32) -> Self {
let abs_code = dll_error_code.unsigned_abs();
match abs_code {
7 => FoEErrorCode::PacketNumberWrong, 10 => FoEErrorCode::NotFound,
12 => FoEErrorCode::AccessDenied,
13 => FoEErrorCode::DiskFull,
14 => FoEErrorCode::Illegal,
15 => FoEErrorCode::PacketNumberWrong,
16 => FoEErrorCode::AlreadyExists,
17 => FoEErrorCode::NoUser,
18 => FoEErrorCode::BootstrapOnly,
19 => FoEErrorCode::NotBootstrap,
20 => FoEErrorCode::NoRights,
21 => FoEErrorCode::ProgramError,
_ => FoEErrorCode::NotDefined,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum SoEErrorCode {
NoError = 0x0000,
NoIDN = 0x1001,
InvalidAccessToElement = 0x1009,
NoName = 0x2001,
NameTransmissionTooShort = 0x2002,
NameTransmissionTooLong = 0x2003,
NameCannotBeChanged = 0x2004,
NameWriteProtected = 0x2005,
AttributeTransmissionTooShort = 0x3002,
AttributeTransmissionTooLong = 0x3003,
AttributeCannotBeChanged = 0x3004,
AttributeWriteProtected = 0x3005,
NoUnits = 0x4001,
UnitTransmissionTooShort = 0x4002,
UnitTransmissionTooLong = 0x4003,
UnitCannotBeChanged = 0x4004,
UnitWriteProtected = 0x4005,
NoMinimumInputValue = 0x5001,
MinValueTooShort = 0x5002,
MinValueTooLong = 0x5003,
MinValueCannotBeChanged = 0x5004,
MinValueWriteProtected = 0x5005,
NoMaximumInputValue = 0x6001,
MaxValueTooShort = 0x6002,
MaxValueTooLong = 0x6003,
MaxValueCannotBeChanged = 0x6004,
MaxValueWriteProtected = 0x6005,
NoOperationData = 0x7001,
OpDataTooShort = 0x7002,
OpDataTooLong = 0x7003,
OpDataCannotBeChanged = 0x7004,
OpDataWriteProtected = 0x7005,
OpDataSmallerThanMin = 0x7006,
OpDataGreaterThanMax = 0x7007,
InvalidDriveNumber = 0x800A,
GeneralError = 0x800B,
NoElementAddressed = 0x800C,
Unknown = 0xFFFF,
}
#[derive(Debug, Clone, Copy)]
pub struct SyncWindowStatus {
pub diff_ns: i32,
pub max_diff_ns: i32,
pub min_diff_ns: i32,
pub in_sync: bool,
pub out_of_sync_count: u32,
}