kcan 0.3.0

CAN controller primitives for actuator and motor control.
Documentation
use std::fmt;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Clone, PartialEq)]
pub enum Error {
    InvalidRange {
        min: f64,
        max: f64,
    },
    InvalidBitWidth(u8),
    InvalidCanId(u32),
    PayloadTooLong {
        len: usize,
    },
    PayloadTooShort {
        expected: usize,
        actual: usize,
    },
    InvalidPayloadLength {
        expected: usize,
        actual: usize,
    },
    InvalidNodeId(u8),
    NonFiniteValue(&'static str),
    UnsupportedMode(u32),
    UnknownParameter(String),
    ReadOnlyParameter(&'static str),
    ParameterTypeMismatch {
        parameter: &'static str,
        expected: &'static str,
        actual: &'static str,
    },
    InvalidParameterValue {
        parameter: &'static str,
        constraint: &'static str,
    },
    InvalidModeTransition {
        from: u8,
        to: u8,
    },
    UnsafeOperation {
        operation: &'static str,
        required: &'static str,
        actual_mode: u8,
    },
    InvalidRefreshRate(f64),
    DuplicateMotorId(u8),
    UnknownMotorId(u8),
    UnknownMotorLabel(String),
    InvalidTraceLine {
        line: usize,
        reason: String,
    },
    Transport(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::InvalidRange { min, max } => {
                write!(
                    f,
                    "invalid range: max ({max}) must be greater than min ({min})"
                )
            }
            Self::InvalidBitWidth(bits) => write!(f, "invalid bit width: {bits}"),
            Self::InvalidCanId(id) => write!(f, "invalid CAN id: 0x{id:X}"),
            Self::PayloadTooLong { len } => write!(f, "CAN payload too long: {len} bytes"),
            Self::PayloadTooShort { expected, actual } => {
                write!(
                    f,
                    "payload too short: expected {expected} bytes, got {actual}"
                )
            }
            Self::InvalidPayloadLength { expected, actual } => {
                write!(
                    f,
                    "invalid payload length: expected exactly {expected} bytes, got {actual}"
                )
            }
            Self::InvalidNodeId(id) => {
                write!(f, "invalid Knott Dynamics node id: {id}; expected 1..63")
            }
            Self::NonFiniteValue(field) => write!(f, "{field} must be finite"),
            Self::UnsupportedMode(mode) => {
                write!(f, "mode 0x{mode:02X} cannot be requested over CAN")
            }
            Self::UnknownParameter(parameter) => {
                write!(f, "unknown Knott Dynamics parameter: {parameter}")
            }
            Self::ReadOnlyParameter(parameter) => {
                write!(f, "Knott Dynamics parameter {parameter} is read-only")
            }
            Self::ParameterTypeMismatch {
                parameter,
                expected,
                actual,
            } => write!(
                f,
                "Knott Dynamics parameter {parameter} expects {expected}, got {actual}"
            ),
            Self::InvalidParameterValue {
                parameter,
                constraint,
            } => write!(
                f,
                "invalid Knott Dynamics value for {parameter}; expected {constraint}"
            ),
            Self::InvalidModeTransition { from, to } => write!(
                f,
                "invalid Knott Dynamics mode transition from 0x{from:02X} to 0x{to:02X}"
            ),
            Self::UnsafeOperation {
                operation,
                required,
                actual_mode,
            } => write!(
                f,
                "unsafe Knott Dynamics {operation}: requires {required}, current mode is 0x{actual_mode:02X}"
            ),
            Self::InvalidRefreshRate(rate) => write!(f, "invalid refresh rate: {rate} Hz"),
            Self::DuplicateMotorId(id) => write!(f, "duplicate motor id: 0x{id:02X}"),
            Self::UnknownMotorId(id) => write!(f, "unknown motor id: 0x{id:02X}"),
            Self::UnknownMotorLabel(label) => write!(f, "unknown motor label: {label}"),
            Self::InvalidTraceLine { line, reason } => {
                write!(f, "invalid CAN trace line {line}: {reason}")
            }
            Self::Transport(message) => write!(f, "CAN transport error: {message}"),
        }
    }
}

impl std::error::Error for Error {}