001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2012. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import edu.wpi.first.wpilibj.Timer;
011
012/**
013 * The MotorSafetyHelper object is constructed for every object that wants to implement the Motor
014 * Safety protocol. The helper object has the code to actually do the timing and call the
015 * motors Stop() method when the timeout expires. The motor object is expected to call the
016 * Feed() method whenever the motors value is updated.
017 *
018 * @author brad
019 */
020public class MotorSafetyHelper {
021
022    double m_expiration;
023    boolean m_enabled;
024    double m_stopTime;
025    MotorSafety m_safeObject;
026    MotorSafetyHelper m_nextHelper;
027    static MotorSafetyHelper m_headHelper = null;
028
029    /**
030     * The constructor for a MotorSafetyHelper object.
031     * The helper object is constructed for every object that wants to implement the Motor
032     * Safety protocol. The helper object has the code to actually do the timing and call the
033     * motors Stop() method when the timeout expires. The motor object is expected to call the
034     * Feed() method whenever the motors value is updated.
035     *
036     * @param safeObject a pointer to the motor object implementing MotorSafety. This is used
037     * to call the Stop() method on the motor.
038     */
039    public MotorSafetyHelper(MotorSafety safeObject) {
040        m_safeObject = safeObject;
041        m_enabled = false;
042        m_expiration = MotorSafety.DEFAULT_SAFETY_EXPIRATION;
043        m_stopTime = Timer.getFPGATimestamp();
044        m_nextHelper = m_headHelper;
045        m_headHelper = this;
046    }
047
048    /**
049     * Feed the motor safety object.
050     * Resets the timer on this object that is used to do the timeouts.
051     */
052    public void feed() {
053        m_stopTime = Timer.getFPGATimestamp() + m_expiration;
054    }
055
056    /**
057     * Set the expiration time for the corresponding motor safety object.
058     * @param expirationTime The timeout value in seconds.
059     */
060    public void setExpiration(double expirationTime) {
061        m_expiration = expirationTime;
062    }
063
064    /**
065     * Retrieve the timeout value for the corresponding motor safety object.
066     * @return the timeout value in seconds.
067     */
068    public double getExpiration() {
069        return m_expiration;
070    }
071
072    /**
073     * Determine of the motor is still operating or has timed out.
074     * @return a true value if the motor is still operating normally and hasn't timed out.
075     */
076    public boolean isAlive() {
077        return !m_enabled || m_stopTime > Timer.getFPGATimestamp();
078    }
079
080    /**
081     * Check if this motor has exceeded its timeout.
082     * This method is called periodically to determine if this motor has exceeded its timeout
083     * value. If it has, the stop method is called, and the motor is shut down until its value is
084     * updated again.
085     */
086    public void check() {
087        if (!m_enabled || RobotState.isDisabled() || RobotState.isTest())
088            return;
089        if (m_stopTime < Timer.getFPGATimestamp()) {
090            System.err.println(m_safeObject.getDescription() + "... Output not updated often enough.");
091
092            m_safeObject.stopMotor();
093        }
094    }
095
096    /**
097     * Enable/disable motor safety for this device
098     * Turn on and off the motor safety option for this PWM object.
099     * @param enabled True if motor safety is enforced for this object
100     */
101    public void setSafetyEnabled(boolean enabled) {
102        m_enabled = enabled;
103    }
104
105    /**
106     * Return the state of the motor safety enabled flag
107     * Return if the motor safety is currently enabled for this devicce.
108     * @return True if motor safety is enforced for this device
109     */
110    public boolean isSafetyEnabled() {
111        return m_enabled;
112    }
113
114    /**
115     * Check the motors to see if any have timed out.
116     * This static  method is called periodically to poll all the motors and stop any that have
117     * timed out.
118     */
119    //TODO: these should be synchronized with the setting methods in case it's called from a different thread
120    public static void checkMotors() {
121        for (MotorSafetyHelper msh = m_headHelper; msh != null; msh = msh.m_nextHelper) {
122            msh.check();
123        }
124    }
125}