use core::fmt;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq)]
pub enum Error {
Config(ConfigError),
Motor(MotorError),
Motion(MotionError),
Trajectory(TrajectoryError),
}
#[derive(Debug, Clone, PartialEq)]
pub enum ConfigError {
ParseError(heapless::String<128>),
InvalidMicrosteps(u16),
MotorNotFound(heapless::String<32>),
TrajectoryNotFound(heapless::String<32>),
DuplicateMotorName(heapless::String<32>),
DuplicateTrajectoryName(heapless::String<32>),
InvalidVelocityPercent(u8),
InvalidAccelerationPercent(u8),
InvalidGearRatio(f32),
InvalidMaxVelocity(f32),
InvalidMaxAcceleration(f32),
InvalidSoftLimits {
min: f32,
max: f32,
},
#[cfg(feature = "std")]
IoError(heapless::String<128>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum MotorError {
PinError,
InvalidState(heapless::String<32>),
NotInitialized,
LimitExceeded {
position: i64,
limit: i64,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum MotionError {
VelocityExceedsLimit {
requested: f32,
max: f32,
},
AccelerationExceedsLimit {
requested: f32,
max: f32,
},
MoveTooShort {
steps: i64,
minimum: i64,
},
Overflow,
}
#[derive(Debug, Clone, PartialEq)]
pub enum TrajectoryError {
MotorNotFound {
trajectory: heapless::String<32>,
motor: heapless::String<32>,
},
TargetExceedsLimits {
target: f32,
min: f32,
max: f32,
},
EmptyWaypoints,
TooManyWaypoints,
InvalidName(heapless::String<64>),
Empty,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Config(e) => write!(f, "Configuration error: {}", e),
Error::Motor(e) => write!(f, "Motor error: {}", e),
Error::Motion(e) => write!(f, "Motion error: {}", e),
Error::Trajectory(e) => write!(f, "Trajectory error: {}", e),
}
}
}
impl fmt::Display for ConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConfigError::ParseError(msg) => write!(f, "Parse error: {}", msg),
ConfigError::InvalidMicrosteps(v) => {
write!(f, "Invalid microsteps: {}. Valid values: 1, 2, 4, 8, 16, 32, 64, 128, 256", v)
}
ConfigError::MotorNotFound(name) => write!(f, "Motor '{}' not found", name),
ConfigError::TrajectoryNotFound(name) => write!(f, "Trajectory '{}' not found", name),
ConfigError::DuplicateMotorName(name) => write!(f, "Duplicate motor name: '{}'", name),
ConfigError::DuplicateTrajectoryName(name) => write!(f, "Duplicate trajectory name: '{}'", name),
ConfigError::InvalidVelocityPercent(v) => write!(f, "Invalid velocity percent: {}. Must be 1-200", v),
ConfigError::InvalidAccelerationPercent(v) => write!(f, "Invalid acceleration percent: {}. Must be 1-200", v),
ConfigError::InvalidGearRatio(v) => write!(f, "Invalid gear ratio: {}. Must be > 0", v),
ConfigError::InvalidMaxVelocity(v) => write!(f, "Invalid max velocity: {}. Must be > 0", v),
ConfigError::InvalidMaxAcceleration(v) => write!(f, "Invalid max acceleration: {}. Must be > 0", v),
ConfigError::InvalidSoftLimits { min, max } => {
write!(f, "Invalid soft limits: min ({}) must be < max ({})", min, max)
}
#[cfg(feature = "std")]
ConfigError::IoError(msg) => write!(f, "I/O error: {}", msg),
}
}
}
impl fmt::Display for MotorError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MotorError::PinError => write!(f, "GPIO pin operation failed"),
MotorError::InvalidState(state) => write!(f, "Invalid motor state: {}", state),
MotorError::NotInitialized => write!(f, "Motor not initialized"),
MotorError::LimitExceeded { position, limit } => {
write!(f, "Position {} exceeds limit {}", position, limit)
}
}
}
}
impl fmt::Display for MotionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MotionError::VelocityExceedsLimit { requested, max } => {
write!(f, "Requested velocity {} exceeds maximum {}", requested, max)
}
MotionError::AccelerationExceedsLimit { requested, max } => {
write!(f, "Requested acceleration {} exceeds maximum {}", requested, max)
}
MotionError::MoveTooShort { steps, minimum } => {
write!(f, "Move of {} steps too short, minimum is {}", steps, minimum)
}
MotionError::Overflow => write!(f, "Motion profile computation overflow"),
}
}
}
impl fmt::Display for TrajectoryError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TrajectoryError::MotorNotFound { trajectory, motor } => {
write!(f, "Trajectory '{}' references unknown motor '{}'", trajectory, motor)
}
TrajectoryError::TargetExceedsLimits { target, min, max } => {
write!(f, "Target position {} exceeds limits [{}, {}]", target, min, max)
}
TrajectoryError::EmptyWaypoints => write!(f, "Waypoint list is empty"),
TrajectoryError::TooManyWaypoints => {
write!(f, "Too many waypoints (max 32)")
}
TrajectoryError::InvalidName(name) => {
write!(f, "Invalid trajectory name or configuration: {}", name)
}
TrajectoryError::Empty => write!(f, "Trajectory is empty (no waypoints or target)"),
}
}
}
impl From<ConfigError> for Error {
fn from(e: ConfigError) -> Self {
Error::Config(e)
}
}
impl From<MotorError> for Error {
fn from(e: MotorError) -> Self {
Error::Motor(e)
}
}
impl From<MotionError> for Error {
fn from(e: MotionError) -> Self {
Error::Motion(e)
}
}
impl From<TrajectoryError> for Error {
fn from(e: TrajectoryError) -> Self {
Error::Trajectory(e)
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
#[cfg(feature = "std")]
impl std::error::Error for ConfigError {}
#[cfg(feature = "std")]
impl std::error::Error for MotorError {}
#[cfg(feature = "std")]
impl std::error::Error for MotionError {}
#[cfg(feature = "std")]
impl std::error::Error for TrajectoryError {}