use crate::error::{ConfigError, Error, Result, TrajectoryError};
use super::SystemConfig;
pub fn validate_config(config: &SystemConfig) -> Result<()> {
for (name, motor) in config.motors.iter() {
validate_motor(name.as_str(), motor)?;
}
for (name, traj) in config.trajectories.iter() {
validate_trajectory(name.as_str(), traj, config)?;
}
for (name, seq) in config.sequences.iter() {
validate_sequence(name.as_str(), seq, config)?;
}
Ok(())
}
fn validate_motor(_name: &str, config: &super::MotorConfig) -> Result<()> {
if config.gear_ratio <= 0.0 {
return Err(Error::Config(ConfigError::InvalidGearRatio(config.gear_ratio)));
}
if config.max_velocity.0 <= 0.0 {
return Err(Error::Config(ConfigError::InvalidMaxVelocity(
config.max_velocity.0,
)));
}
if config.max_acceleration.0 <= 0.0 {
return Err(Error::Config(ConfigError::InvalidMaxAcceleration(
config.max_acceleration.0,
)));
}
if let Some(ref limits) = config.limits {
if !limits.is_valid() {
return Err(Error::Config(ConfigError::InvalidSoftLimits {
min: limits.min.0,
max: limits.max.0,
}));
}
}
Ok(())
}
fn validate_trajectory(
name: &str,
traj: &super::TrajectoryConfig,
config: &SystemConfig,
) -> Result<()> {
if config.motor(traj.motor.as_str()).is_none() {
return Err(Error::Trajectory(TrajectoryError::MotorNotFound {
trajectory: heapless::String::try_from(name).unwrap_or_default(),
motor: traj.motor.clone(),
}));
}
if traj.velocity_percent == 0 || traj.velocity_percent > 200 {
return Err(Error::Config(ConfigError::InvalidVelocityPercent(
traj.velocity_percent,
)));
}
if traj.acceleration_percent == 0 || traj.acceleration_percent > 200 {
return Err(Error::Config(ConfigError::InvalidAccelerationPercent(
traj.acceleration_percent,
)));
}
if let Some(motor) = config.motor(traj.motor.as_str()) {
if let Some(ref limits) = motor.limits {
if !limits.contains(traj.target_degrees) {
if limits.policy == super::LimitPolicy::Reject {
return Err(Error::Trajectory(TrajectoryError::TargetExceedsLimits {
target: traj.target_degrees.0,
min: limits.min.0,
max: limits.max.0,
}));
}
}
}
}
Ok(())
}
fn validate_sequence(
name: &str,
seq: &super::WaypointTrajectory,
config: &SystemConfig,
) -> Result<()> {
if config.motor(seq.motor.as_str()).is_none() {
return Err(Error::Trajectory(TrajectoryError::MotorNotFound {
trajectory: heapless::String::try_from(name).unwrap_or_default(),
motor: seq.motor.clone(),
}));
}
if seq.waypoints.is_empty() {
return Err(Error::Trajectory(TrajectoryError::EmptyWaypoints));
}
if seq.velocity_percent == 0 || seq.velocity_percent > 200 {
return Err(Error::Config(ConfigError::InvalidVelocityPercent(
seq.velocity_percent,
)));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_invalid_gear_ratio() {
use crate::config::units::{DegreesPerSec, DegreesPerSecSquared, Microsteps};
use crate::config::MotorConfig;
let config = MotorConfig {
name: heapless::String::try_from("test").unwrap(),
steps_per_revolution: 200,
microsteps: Microsteps::SIXTEENTH,
gear_ratio: -1.0, max_velocity: DegreesPerSec(360.0),
max_acceleration: DegreesPerSecSquared(720.0),
invert_direction: false,
limits: None,
backlash_compensation: None,
};
let result = validate_motor("test", &config);
assert!(matches!(
result,
Err(Error::Config(ConfigError::InvalidGearRatio(_)))
));
}
}