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