use crate::{
bindings,
error::{get_errno, Error},
rtos::DataSource,
};
pub struct Motor {
port: u8,
}
impl Motor {
pub unsafe fn new(
port: u8,
gearset: Gearset,
encoder_units: EncoderUnits,
reverse: bool,
) -> Result<Self, MotorError> {
let mut motor = Self { port };
motor.set_reversed(reverse)?;
motor.set_gearing(gearset)?;
match unsafe { bindings::motor_set_encoder_units(port, encoder_units.into()) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(motor),
}
}
pub fn move_i8(&mut self, voltage: i8) -> Result<(), MotorError> {
match unsafe { bindings::motor_move(self.port, voltage as i32) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn move_absolute(&mut self, position: f64, velocity: i32) -> Result<(), MotorError> {
match unsafe { bindings::motor_move_absolute(self.port, position, velocity) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn move_relative(&mut self, position: f64, velocity: i32) -> Result<(), MotorError> {
match unsafe { bindings::motor_move_relative(self.port, position, velocity) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn move_velocity(&mut self, velocity: i32) -> Result<(), MotorError> {
match unsafe { bindings::motor_move_velocity(self.port, velocity) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn move_voltage(&mut self, voltage: i32) -> Result<(), MotorError> {
match unsafe { bindings::motor_move_voltage(self.port, voltage) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn modify_profiled_velocity(&mut self, velocity: i32) -> Result<(), MotorError> {
match unsafe { bindings::motor_modify_profiled_velocity(self.port, velocity) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn get_target_position(&self) -> Result<f64, MotorError> {
match unsafe { bindings::motor_get_target_position(self.port) } {
x if x == bindings::PROS_ERR_F_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_target_velocity(&self) -> Result<i32, MotorError> {
match unsafe { bindings::motor_get_target_velocity(self.port) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_actual_velocity(&self) -> Result<f64, MotorError> {
match unsafe { bindings::motor_get_actual_velocity(self.port) } {
x if x == bindings::PROS_ERR_F_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_current_draw(&self) -> Result<i32, MotorError> {
match unsafe { bindings::motor_get_current_draw(self.port) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_direction(&self) -> Result<Direction, MotorError> {
match unsafe { bindings::motor_get_direction(self.port) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
1 => Ok(Direction::Positive),
-1 => Ok(Direction::Negative),
x => panic!(
"bindings::motor_get_direction returned unexpected value: {}",
x
),
}
}
pub fn get_efficiency(&self) -> Result<f64, MotorError> {
match unsafe { bindings::motor_get_efficiency(self.port) } {
x if x == bindings::PROS_ERR_F_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_position(&self) -> Result<f64, MotorError> {
match unsafe { bindings::motor_get_position(self.port) } {
x if x == bindings::PROS_ERR_F_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_power(&self) -> Result<f64, MotorError> {
match unsafe { bindings::motor_get_power(self.port) } {
x if x == bindings::PROS_ERR_F_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_temperature(&self) -> Result<f64, MotorError> {
match unsafe { bindings::motor_get_temperature(self.port) } {
x if x == bindings::PROS_ERR_F_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_torque(&self) -> Result<f64, MotorError> {
match unsafe { bindings::motor_get_torque(self.port) } {
x if x == bindings::PROS_ERR_F_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_voltage(&self) -> Result<i32, MotorError> {
match unsafe { bindings::motor_get_voltage(self.port) } {
x if x == bindings::PROS_ERR_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn is_over_current(&self) -> Result<bool, MotorError> {
match unsafe { bindings::motor_is_over_current(self.port) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
0 => Ok(false),
_ => Ok(true),
}
}
pub fn is_over_temp(&self) -> Result<bool, MotorError> {
match unsafe { bindings::motor_is_over_temp(self.port) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
0 => Ok(false),
_ => Ok(true),
}
}
pub fn get_brake_mode(&self) -> Result<BrakeMode, MotorError> {
match unsafe { bindings::motor_get_brake_mode(self.port) } {
bindings::motor_brake_mode_e_E_MOTOR_BRAKE_BRAKE => Ok(BrakeMode::Brake),
bindings::motor_brake_mode_e_E_MOTOR_BRAKE_COAST => Ok(BrakeMode::Coast),
bindings::motor_brake_mode_e_E_MOTOR_BRAKE_HOLD => Ok(BrakeMode::Hold),
bindings::motor_brake_mode_e_E_MOTOR_BRAKE_INVALID => Err(MotorError::from_errno()),
x => panic!(
"bindings::motor_get_brake_mode returned unexpected value: {}.",
x
),
}
}
pub fn get_current_limit(&self) -> Result<i32, MotorError> {
match unsafe { bindings::motor_get_current_limit(self.port) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn get_gearing(&self) -> Result<Gearset, MotorError> {
match unsafe { bindings::motor_get_gearing(self.port) } {
bindings::motor_gearset_e_E_MOTOR_GEARSET_36 => Ok(Gearset::SixToOne),
bindings::motor_gearset_e_E_MOTOR_GEARSET_18 => Ok(Gearset::EighteenToOne),
bindings::motor_gearset_e_E_MOTOR_GEARSET_06 => Ok(Gearset::ThirtySixToOne),
bindings::motor_gearset_e_E_MOTOR_GEARSET_INVALID => Err(MotorError::from_errno()),
x => panic!(
"bindings::motor_get_gearing returned unexpected value: {}.",
x
),
}
}
pub fn get_voltage_limit(&self) -> Result<i32, MotorError> {
match unsafe { bindings::motor_get_voltage_limit(self.port) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
x => Ok(x),
}
}
pub fn is_reversed(&self) -> Result<bool, MotorError> {
match unsafe { bindings::motor_is_reversed(self.port) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
0 => Ok(false),
_ => Ok(true),
}
}
pub fn set_brake_mode(&mut self, mode: BrakeMode) -> Result<(), MotorError> {
match unsafe { bindings::motor_set_brake_mode(self.port, mode.into()) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn set_current_limit(&mut self, limit: i32) -> Result<(), MotorError> {
match unsafe { bindings::motor_set_current_limit(self.port, limit) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn set_gearing(&mut self, gearset: Gearset) -> Result<(), MotorError> {
match unsafe { bindings::motor_set_gearing(self.port, gearset.into()) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn set_reversed(&mut self, reverse: bool) -> Result<(), MotorError> {
match unsafe { bindings::motor_set_reversed(self.port, reverse) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn set_voltage_limit(&mut self, limit: i32) -> Result<(), MotorError> {
match unsafe { bindings::motor_set_voltage_limit(self.port, limit) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn set_zero_position(&mut self, position: f64) -> Result<(), MotorError> {
match unsafe { bindings::motor_set_zero_position(self.port, position) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn tare_position(&mut self) -> Result<(), MotorError> {
match unsafe { bindings::motor_tare_position(self.port) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn set_encoder_units(&mut self, units: EncoderUnits) -> Result<(), MotorError> {
match unsafe { bindings::motor_set_encoder_units(self.port, units.into()) } {
bindings::PROS_ERR_ => Err(MotorError::from_errno()),
_ => Ok(()),
}
}
pub fn get_encoder_units(&self) -> Result<EncoderUnits, MotorError> {
match unsafe { bindings::motor_get_encoder_units(self.port) } {
bindings::motor_encoder_units_e_E_MOTOR_ENCODER_COUNTS => {
Ok(EncoderUnits::EncoderTicks)
}
bindings::motor_encoder_units_e_E_MOTOR_ENCODER_DEGREES => Ok(EncoderUnits::Degrees),
bindings::motor_encoder_units_e_E_MOTOR_ENCODER_ROTATIONS => {
Ok(EncoderUnits::Rotations)
}
bindings::motor_encoder_units_e_E_MOTOR_ENCODER_INVALID => {
Err(MotorError::from_errno())
}
x => panic!("bindings:get_encoder_units returned unexpected value {}", x),
}
}
}
impl DataSource for Motor {
type Data = MotorData;
type Error = MotorError;
fn read(&self) -> Result<Self::Data, Self::Error> {
Ok(MotorData {
target_position: self.get_target_position()?,
target_velocity: self.get_target_velocity()?,
actual_velocity: self.get_actual_velocity()?,
current_draw: self.get_current_draw()?,
direction: self.get_direction()?,
efficiency: self.get_efficiency()?,
position: self.get_position()?,
power: self.get_power()?,
temperature: self.get_temperature()?,
torque: self.get_torque()?,
voltage: self.get_voltage()?,
over_current: self.is_over_current()?,
over_temp: self.is_over_temp()?,
brake_mode: self.get_brake_mode()?,
current_limit: self.get_current_limit()?,
voltage_limit: self.get_voltage_limit()?,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MotorData {
pub target_position: f64,
pub target_velocity: i32,
pub actual_velocity: f64,
pub current_draw: i32,
pub direction: Direction,
pub efficiency: f64,
pub position: f64,
pub power: f64,
pub temperature: f64,
pub torque: f64,
pub voltage: i32,
pub over_current: bool,
pub over_temp: bool,
pub brake_mode: BrakeMode,
pub current_limit: i32,
pub voltage_limit: i32,
}
#[derive(Debug)]
pub enum MotorError {
PortOutOfRange,
PortNotMotor,
Unknown(i32),
}
impl MotorError {
fn from_errno() -> Self {
match get_errno() {
libc::ENXIO => Self::PortOutOfRange,
libc::ENODEV => Self::PortNotMotor,
x => Self::Unknown(x),
}
}
}
impl From<MotorError> for Error {
fn from(err: MotorError) -> Self {
match err {
MotorError::PortOutOfRange => Error::Custom("port out of range".into()),
MotorError::PortNotMotor => Error::Custom("port not a motor".into()),
MotorError::Unknown(n) => Error::System(n),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BrakeMode {
Coast,
Brake,
Hold,
}
impl From<BrakeMode> for bindings::motor_brake_mode_e {
fn from(mode: BrakeMode) -> Self {
match mode {
BrakeMode::Coast => bindings::motor_brake_mode_e_E_MOTOR_BRAKE_COAST,
BrakeMode::Brake => bindings::motor_brake_mode_e_E_MOTOR_BRAKE_BRAKE,
BrakeMode::Hold => bindings::motor_brake_mode_e_E_MOTOR_BRAKE_HOLD,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Gearset {
SixToOne,
EighteenToOne,
ThirtySixToOne,
}
impl From<Gearset> for bindings::motor_gearset_e {
fn from(gearset: Gearset) -> Self {
match gearset {
Gearset::SixToOne => bindings::motor_gearset_e_E_MOTOR_GEARSET_06,
Gearset::EighteenToOne => bindings::motor_gearset_e_E_MOTOR_GEARSET_18,
Gearset::ThirtySixToOne => bindings::motor_gearset_e_E_MOTOR_GEARSET_36,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
Positive,
Negative,
}
#[derive(Clone, Copy)]
pub enum EncoderUnits {
EncoderTicks,
Degrees,
Rotations,
}
impl From<EncoderUnits> for bindings::motor_encoder_units_e {
fn from(units: EncoderUnits) -> Self {
match units {
EncoderUnits::EncoderTicks => bindings::motor_encoder_units_e_E_MOTOR_ENCODER_COUNTS,
EncoderUnits::Degrees => bindings::motor_encoder_units_e_E_MOTOR_ENCODER_DEGREES,
EncoderUnits::Rotations => bindings::motor_encoder_units_e_E_MOTOR_ENCODER_ROTATIONS,
}
}
}