///|
/// A CAN frame kind.
pub enum FrameKind {
Data
Remote
Error
}
///|
/// A CAN bus protocol version.
pub enum Protocol {
Can20
CanFd
}
///|
/// A normalized CAN frame.
pub struct Frame {
id : UInt
extended : Bool
kind : FrameKind
protocol : Protocol
bitrate_switch : Bool
error_state_indicator : Bool
data : Array[Byte]
}
///|
/// A frame validation error.
pub suberror FrameError {
InvalidIdentifier
InvalidLength
} derive(Debug)
///|
/// Create a classic CAN data frame.
pub fn data_frame(
id : UInt,
data : Array[Byte],
extended? : Bool = false,
) -> Frame raise FrameError {
validate_id(id, extended)
if data.length() > 8 {
raise InvalidLength
}
{
id,
extended,
kind: Data,
protocol: Can20,
bitrate_switch: false,
error_state_indicator: false,
data: data.copy(),
}
}
///|
/// Create a CAN-FD data frame.
pub fn fd_frame(
id : UInt,
data : Array[Byte],
extended? : Bool = false,
bitrate_switch? : Bool = false,
error_state_indicator? : Bool = false,
) -> Frame raise FrameError {
validate_id(id, extended)
if data.length() > 64 {
raise InvalidLength
}
{
id,
extended,
kind: Data,
protocol: CanFd,
bitrate_switch,
error_state_indicator,
data: data.copy(),
}
}
///|
/// Create a remote request frame.
pub fn remote_frame(
id : UInt,
extended? : Bool = false,
) -> Frame raise FrameError {
validate_id(id, extended)
{
id,
extended,
kind: Remote,
protocol: Can20,
bitrate_switch: false,
error_state_indicator: false,
data: [],
}
}
///|
/// Create a local error frame for simulation and diagnostics.
pub fn error_frame(code : Byte) -> Frame {
{
id: 0,
extended: false,
kind: Error,
protocol: Can20,
bitrate_switch: false,
error_state_indicator: false,
data: [code],
}
}
///|
fn validate_id(id : UInt, extended : Bool) -> Unit raise FrameError {
if extended {
if id > 0x1FFFFFFF {
raise InvalidIdentifier
}
} else if id > 0x7FF {
raise InvalidIdentifier
}
}
///|
/// The arbitration identifier.
pub fn Frame::id(self : Frame) -> UInt {
self.id
}
///|
/// Whether the frame uses the 29-bit identifier format.
pub fn Frame::is_extended(self : Frame) -> Bool {
self.extended
}
///|
/// Return the frame kind.
pub fn Frame::kind(self : Frame) -> FrameKind {
self.kind
}
///|
/// Return the protocol version.
pub fn Frame::protocol(self : Frame) -> Protocol {
self.protocol
}
///|
/// Return a defensive copy of the payload.
pub fn Frame::data(self : Frame) -> Array[Byte] {
self.data.copy()
}
///|
/// Return whether the CAN-FD bit-rate switch is set.
pub fn Frame::bitrate_switch(self : Frame) -> Bool {
self.bitrate_switch
}
///|
/// Return whether the CAN-FD error-state indicator is set.
pub fn Frame::error_state_indicator(self : Frame) -> Bool {
self.error_state_indicator
}
///|
/// Return whether this frame carries application data.
pub fn Frame::is_data(self : Frame) -> Bool {
self.kind is Data
}
///|
/// Return whether this frame is a remote request.
pub fn Frame::is_remote(self : Frame) -> Bool {
self.kind is Remote
}
///|
/// Return whether this frame is a local simulation error.
pub fn Frame::is_error(self : Frame) -> Bool {
self.kind is Error
}
///|
/// Return the data length code for this frame.
pub fn Frame::dlc(self : Frame) -> Byte {
match self.protocol {
Can20 => self.data.length().to_byte()
CanFd => fd_dlc(self.data.length())
}
}
///|
fn fd_dlc(length : Int) -> Byte {
if length <= 8 {
length.to_byte()
} else if length <= 12 {
9
} else if length <= 16 {
10
} else if length <= 20 {
11
} else if length <= 24 {
12
} else if length <= 32 {
13
} else if length <= 48 {
14
} else {
15
}
}
///|
/// Decode a CAN-FD DLC into its payload capacity.
pub fn fd_length_from_dlc(dlc : Byte) -> Int {
if dlc <= 8 {
dlc.to_int()
} else if dlc == 9 {
12
} else if dlc == 10 {
16
} else if dlc == 11 {
20
} else if dlc == 12 {
24
} else if dlc == 13 {
32
} else if dlc == 14 {
48
} else {
64
}
}