use try_from::TryFrom;
use super::CANFrame;
#[inline(always)]
fn get_data(frame: &CANFrame, idx: u8) -> Result<u8, CANErrorDecodingFailure> {
Ok(*try!(frame.data().get(idx as usize).ok_or(CANErrorDecodingFailure::NotEnoughData(idx))))
}
#[derive(Copy, Clone, Debug)]
pub enum CANErrorDecodingFailure {
NotAnError,
UnknownErrorType(u32),
NotEnoughData(u8),
InvalidControllerProblem,
InvlaidViolationType,
InvalidLocation,
InvalidTransceiverError,
}
#[derive(Copy, Clone, Debug)]
pub enum CANError {
TransmitTimeout,
LostArbitration(u8),
ControllerProblem(ControllerProblem),
ProtocolViolation {
vtype: ViolationType,
location: Location,
},
TransceiverError,
NoAck,
BusOff,
BusError,
Restarted,
Unknown(u32),
}
#[derive(Copy, Clone, Debug)]
pub enum ControllerProblem {
Unspecified,
ReceiveBufferOverflow,
TransmitBufferOverflow,
ReceiveErrorWarning,
TransmitErrorWarning,
ReceiveErrorPassive,
TransmitErrorPassive,
Active,
}
impl TryFrom<u8> for ControllerProblem {
type Err = CANErrorDecodingFailure;
fn try_from(val: u8) -> Result<ControllerProblem, CANErrorDecodingFailure> {
Ok(match val {
0x00 => ControllerProblem::Unspecified,
0x01 => ControllerProblem::ReceiveBufferOverflow,
0x02 => ControllerProblem::TransmitBufferOverflow,
0x04 => ControllerProblem::ReceiveErrorWarning,
0x08 => ControllerProblem::TransmitErrorWarning,
0x10 => ControllerProblem::ReceiveErrorPassive,
0x20 => ControllerProblem::TransmitErrorPassive,
0x40 => ControllerProblem::Active,
_ => return Err(CANErrorDecodingFailure::InvalidControllerProblem),
})
}
}
#[derive(Copy, Clone, Debug)]
pub enum ViolationType {
Unspecified, SingleBitError, FrameFormatError, BitStuffingError, UnableToSendDominantBit, UnableToSendRecessiveBit, BusOverload, Active, TransmissionError, }
impl TryFrom<u8> for ViolationType {
type Err = CANErrorDecodingFailure;
fn try_from(val: u8) -> Result<ViolationType, CANErrorDecodingFailure> {
Ok(match val {
0x00 => ViolationType::Unspecified,
0x01 => ViolationType::SingleBitError,
0x02 => ViolationType::FrameFormatError,
0x04 => ViolationType::BitStuffingError,
0x08 => ViolationType::UnableToSendDominantBit,
0x10 => ViolationType::UnableToSendRecessiveBit,
0x20 => ViolationType::BusOverload,
0x40 => ViolationType::Active,
0x80 => ViolationType::TransmissionError,
_ => return Err(CANErrorDecodingFailure::InvlaidViolationType),
})
}
}
#[derive(Copy, Clone, Debug)]
pub enum Location {
Unspecified,
StartOfFrame,
Id2821,
Id2018,
SubstituteRtr,
IdentifierExtension,
Id1713,
Id1205,
Id0400,
Rtr,
Reserved1,
Reserved0,
DataLengthCode,
DataSection,
CrcSequence,
CrcDelimiter,
AckSlot,
AckDelimiter,
EndOfFrame,
Intermission,
}
impl TryFrom<u8> for Location {
type Err = CANErrorDecodingFailure;
fn try_from(val: u8) -> Result<Location, CANErrorDecodingFailure> {
Ok(match val {
0x00 => Location::Unspecified,
0x03 => Location::StartOfFrame,
0x02 => Location::Id2821,
0x06 => Location::Id2018,
0x04 => Location::SubstituteRtr,
0x05 => Location::IdentifierExtension,
0x07 => Location::Id1713,
0x0F => Location::Id1205,
0x0E => Location::Id0400,
0x0C => Location::Rtr,
0x0D => Location::Reserved1,
0x09 => Location::Reserved0,
0x0B => Location::DataLengthCode,
0x0A => Location::DataSection,
0x08 => Location::CrcSequence,
0x18 => Location::CrcDelimiter,
0x19 => Location::AckSlot,
0x1B => Location::AckDelimiter,
0x1A => Location::EndOfFrame,
0x12 => Location::Intermission,
_ => return Err(CANErrorDecodingFailure::InvalidLocation),
})
}
}
pub enum TransceiverError {
Unspecified,
CanHighNoWire,
CanHighShortToBat,
CanHighShortToVcc,
CanHighShortToGnd,
CanLowNoWire,
CanLowShortToBat,
CanLowShortToVcc,
CanLowShortToGnd,
CanLowShortToCanHigh,
}
impl TryFrom<u8> for TransceiverError {
type Err = CANErrorDecodingFailure;
fn try_from(val: u8) -> Result<TransceiverError, CANErrorDecodingFailure> {
Ok(match val {
0x00 => TransceiverError::Unspecified,
0x04 => TransceiverError::CanHighNoWire,
0x05 => TransceiverError::CanHighShortToBat,
0x06 => TransceiverError::CanHighShortToVcc,
0x07 => TransceiverError::CanHighShortToGnd,
0x40 => TransceiverError::CanLowNoWire,
0x50 => TransceiverError::CanLowShortToBat,
0x60 => TransceiverError::CanLowShortToVcc,
0x70 => TransceiverError::CanLowShortToGnd,
0x80 => TransceiverError::CanLowShortToCanHigh,
_ => return Err(CANErrorDecodingFailure::InvalidTransceiverError),
})
}
}
impl CANError {
pub fn from_frame(frame: &CANFrame) -> Result<CANError, CANErrorDecodingFailure> {
if !frame.is_error() {
return Err(CANErrorDecodingFailure::NotAnError);
}
match frame.err() {
0x00000001 => Ok(CANError::TransmitTimeout),
0x00000002 => Ok(CANError::LostArbitration(try!(get_data(frame, 0)))),
0x00000004 => {
Ok(CANError::ControllerProblem(try!(ControllerProblem::try_from
(try! (get_data(frame, 1))))))
}
0x00000008 => {
Ok(CANError::ProtocolViolation {
vtype: try!(ViolationType::try_from(try!(get_data(frame, 2)))),
location: try!(Location::try_from(try!(get_data(frame, 3)))),
})
}
0x00000010 => Ok(CANError::TransceiverError),
0x00000020 => Ok(CANError::NoAck),
0x00000040 => Ok(CANError::BusOff),
0x00000080 => Ok(CANError::BusError),
0x00000100 => Ok(CANError::Restarted),
e => Err(CANErrorDecodingFailure::UnknownErrorType(e)),
}
}
}
pub trait ControllerSpecificErrorInformation {
fn get_ctrl_err(&self) -> Option<&[u8]>;
}
impl ControllerSpecificErrorInformation for CANFrame {
#[inline]
fn get_ctrl_err(&self) -> Option<&[u8]> {
let data = self.data();
if data.len() != 8 {
None
} else {
Some(&data[5..])
}
}
}