use super::CanFrame;
use embedded_hal::can::Frame;
use std::{
convert::TryFrom,
error,
fmt,
io,
};
#[inline]
fn get_data(frame: &CanFrame, idx: u8) -> Result<u8, CanErrorDecodingFailure> {
Ok(*(frame.data()
.get(idx as usize)
.ok_or(CanErrorDecodingFailure::NotEnoughData(idx)))?)
}
#[derive(Copy, Clone, Debug)]
pub enum CanErrorDecodingFailure {
NotAnError,
UnknownErrorType(u32),
NotEnoughData(u8),
InvalidControllerProblem,
InvalidViolationType,
InvalidLocation,
InvalidTransceiverError,
}
impl error::Error for CanErrorDecodingFailure {}
impl fmt::Display for CanErrorDecodingFailure {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
CanErrorDecodingFailure::NotAnError => "CAN frame is not an error",
CanErrorDecodingFailure::UnknownErrorType(_) => "unknown error type",
CanErrorDecodingFailure::NotEnoughData(_) => "not enough data",
CanErrorDecodingFailure::InvalidControllerProblem => "not a valid controller problem",
CanErrorDecodingFailure::InvalidViolationType => "not a valid violation type",
CanErrorDecodingFailure::InvalidLocation => "not a valid location",
CanErrorDecodingFailure::InvalidTransceiverError => "not a valid transceiver error",
};
write!(f, "{}", msg)
}
}
#[derive(Copy, Clone, Debug)]
pub enum CanError {
TransmitTimeout,
LostArbitration(u8),
ControllerProblem(ControllerProblem),
ProtocolViolation {
vtype: ViolationType,
location: Location,
},
TransceiverError,
NoAck,
BusOff,
BusError,
Restarted,
Unknown(u32),
}
impl error::Error for CanError {}
impl fmt::Display for CanError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CanError::TransmitTimeout => write!(f, "transmission timeout"),
CanError::LostArbitration(n) => write!(f, "arbitration lost after {} bits", n),
CanError::ControllerProblem(e) => write!(f, "controller problem: {}", e),
CanError::ProtocolViolation { vtype, location } => {
write!(f, "protocol violation at {}: {}", location, vtype)
}
CanError::TransceiverError => write!(f, "transceiver error"),
CanError::NoAck => write!(f, "no ack"),
CanError::BusOff => write!(f, "bus off"),
CanError::BusError => write!(f, "bus error"),
CanError::Restarted => write!(f, "restarted"),
CanError::Unknown(errno) => write!(f, "unknown error ({})", errno),
}
}
}
impl embedded_hal::can::Error for CanError {
fn kind(&self) -> embedded_hal::can::ErrorKind {
match *self {
CanError::ControllerProblem(cp) => {
match cp {
ControllerProblem::ReceiveBufferOverflow | ControllerProblem::TransmitBufferOverflow => embedded_hal::can::ErrorKind::Overrun,
ControllerProblem::Unspecified | _ => embedded_hal::can::ErrorKind::Other,
}
},
CanError::NoAck => embedded_hal::can::ErrorKind::Acknowledge,
_ => embedded_hal::can::ErrorKind::Other,
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum ControllerProblem {
Unspecified,
ReceiveBufferOverflow,
TransmitBufferOverflow,
ReceiveErrorWarning,
TransmitErrorWarning,
ReceiveErrorPassive,
TransmitErrorPassive,
Active,
}
impl error::Error for ControllerProblem {}
impl fmt::Display for ControllerProblem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
ControllerProblem::Unspecified => "unspecified controller problem",
ControllerProblem::ReceiveBufferOverflow => "receive buffer overflow",
ControllerProblem::TransmitBufferOverflow => "transmit buffer overflow",
ControllerProblem::ReceiveErrorWarning => "ERROR WARNING (receive)",
ControllerProblem::TransmitErrorWarning => "ERROR WARNING (transmit)",
ControllerProblem::ReceiveErrorPassive => "ERROR PASSIVE (receive)",
ControllerProblem::TransmitErrorPassive => "ERROR PASSIVE (transmit)",
ControllerProblem::Active => "ERROR ACTIVE",
};
write!(f, "{}", msg)
}
}
impl TryFrom<u8> for ControllerProblem {
type Error = CanErrorDecodingFailure;
fn try_from(val: u8) -> Result<Self, Self::Error> {
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 error::Error for ViolationType {}
impl fmt::Display for ViolationType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
ViolationType::Unspecified => "unspecified",
ViolationType::SingleBitError => "single bit error",
ViolationType::FrameFormatError => "frame format error",
ViolationType::BitStuffingError => "bit stuffing error",
ViolationType::UnableToSendDominantBit => "unable to send dominant bit",
ViolationType::UnableToSendRecessiveBit => "unable to send recessive bit",
ViolationType::BusOverload => "bus overload",
ViolationType::Active => "active",
ViolationType::TransmissionError => "transmission error",
};
write!(f, "{}", msg)
}
}
impl TryFrom<u8> for ViolationType {
type Error = CanErrorDecodingFailure;
fn try_from(val: u8) -> Result<Self, Self::Error> {
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::InvalidViolationType),
})
}
}
#[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 fmt::Display for Location {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
Location::Unspecified => "unspecified location",
Location::StartOfFrame => "start of frame",
Location::Id2821 => "ID, bits 28-21",
Location::Id2018 => "ID, bits 20-18",
Location::SubstituteRtr => "substitute RTR bit",
Location::IdentifierExtension => "ID, extension",
Location::Id1713 => "ID, bits 17-13",
Location::Id1205 => "ID, bits 12-05",
Location::Id0400 => "ID, bits 04-00",
Location::Rtr => "RTR bit",
Location::Reserved1 => "reserved bit 1",
Location::Reserved0 => "reserved bit 0",
Location::DataLengthCode => "data length code",
Location::DataSection => "data section",
Location::CrcSequence => "CRC sequence",
Location::CrcDelimiter => "CRC delimiter",
Location::AckSlot => "ACK slot",
Location::AckDelimiter => "ACK delimiter",
Location::EndOfFrame => "end of frame",
Location::Intermission => "intermission",
};
write!(f, "{}", msg)
}
}
impl TryFrom<u8> for Location {
type Error = CanErrorDecodingFailure;
fn try_from(val: u8) -> Result<Self, Self::Error> {
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 Error = CanErrorDecodingFailure;
fn try_from(val: u8) -> Result<Self, Self::Error> {
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<Self, CanErrorDecodingFailure> {
if !frame.is_error() {
return Err(CanErrorDecodingFailure::NotAnError);
}
match frame.err() {
0x00000001 => Ok(CanError::TransmitTimeout),
0x00000002 => Ok(CanError::LostArbitration(get_data(frame, 0)?)),
0x00000004 => {
Ok(CanError::ControllerProblem(ControllerProblem::try_from(get_data(frame, 1)?)?))
}
0x00000008 => {
Ok(CanError::ProtocolViolation {
vtype: ViolationType::try_from(get_data(frame, 2)?)?,
location: Location::try_from(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..])
}
}
}
#[derive(Debug)]
pub enum CanSocketOpenError {
LookupError(nix::Error),
IOError(io::Error),
}
impl fmt::Display for CanSocketOpenError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CanSocketOpenError::LookupError(ref e) => write!(f, "CAN Device not found: {}", e),
CanSocketOpenError::IOError(ref e) => write!(f, "IO: {}", e),
}
}
}
impl error::Error for CanSocketOpenError {}
#[derive(Debug, Copy, Clone)]
pub enum ConstructionError {
IDTooLarge,
TooMuchData,
}
impl fmt::Display for ConstructionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ConstructionError::IDTooLarge => write!(f, "CAN ID too large"),
ConstructionError::TooMuchData => {
write!(f, "Payload is larger than CAN maximum of 8 bytes")
}
}
}
}
impl error::Error for ConstructionError {}
impl From<nix::Error> for CanSocketOpenError {
fn from(e: nix::Error) -> CanSocketOpenError {
CanSocketOpenError::LookupError(e)
}
}
impl From<io::Error> for CanSocketOpenError {
fn from(e: io::Error) -> CanSocketOpenError {
CanSocketOpenError::IOError(e)
}
}