001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) 2008-2018 FIRST. 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 java.util.LinkedHashSet; 011import java.util.Set; 012 013/** 014 * The MotorSafetyHelper object is constructed for every object that wants to implement the Motor 015 * Safety protocol. The helper object has the code to actually do the timing and call the motors 016 * Stop() method when the timeout expires. The motor object is expected to call the Feed() method 017 * whenever the motors value is updated. 018 */ 019public final class MotorSafetyHelper { 020 private double m_expiration; 021 private boolean m_enabled; 022 private double m_stopTime; 023 private final Object m_thisMutex = new Object(); 024 private final MotorSafety m_safeObject; 025 private static final Set<MotorSafetyHelper> m_helperList = new LinkedHashSet<>(); 026 private static final Object m_listMutex = new Object(); 027 028 /** 029 * The constructor for a MotorSafetyHelper object. The helper object is constructed for every 030 * object that wants to implement the Motor Safety protocol. The helper object has the code to 031 * actually do the timing and call the motors Stop() method when the timeout expires. The motor 032 * object is expected to call the Feed() method whenever the motors value is updated. 033 * 034 * @param safeObject a pointer to the motor object implementing MotorSafety. This is used to call 035 * 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 043 synchronized (m_listMutex) { 044 m_helperList.add(this); 045 } 046 } 047 048 /** 049 * Feed the motor safety object. Resets the timer on this object that is used to do the timeouts. 050 */ 051 public void feed() { 052 synchronized (m_thisMutex) { 053 m_stopTime = Timer.getFPGATimestamp() + m_expiration; 054 } 055 } 056 057 /** 058 * Set the expiration time for the corresponding motor safety object. 059 * 060 * @param expirationTime The timeout value in seconds. 061 */ 062 public void setExpiration(double expirationTime) { 063 synchronized (m_thisMutex) { 064 m_expiration = expirationTime; 065 } 066 } 067 068 /** 069 * Retrieve the timeout value for the corresponding motor safety object. 070 * 071 * @return the timeout value in seconds. 072 */ 073 public double getExpiration() { 074 synchronized (m_thisMutex) { 075 return m_expiration; 076 } 077 } 078 079 /** 080 * Determine of the motor is still operating or has timed out. 081 * 082 * @return a true value if the motor is still operating normally and hasn't timed out. 083 */ 084 public boolean isAlive() { 085 synchronized (m_thisMutex) { 086 return !m_enabled || m_stopTime > Timer.getFPGATimestamp(); 087 } 088 } 089 090 /** 091 * Check if this motor has exceeded its timeout. This method is called periodically to determine 092 * if this motor has exceeded its timeout value. If it has, the stop method is called, and the 093 * motor is shut down until its value is updated again. 094 */ 095 public void check() { 096 boolean enabled; 097 double stopTime; 098 099 synchronized (m_thisMutex) { 100 enabled = m_enabled; 101 stopTime = m_stopTime; 102 } 103 104 if (!enabled || RobotState.isDisabled() || RobotState.isTest()) { 105 return; 106 } 107 if (stopTime < Timer.getFPGATimestamp()) { 108 DriverStation.reportError(m_safeObject.getDescription() + "... Output not updated often " 109 + "enough.", false); 110 111 m_safeObject.stopMotor(); 112 } 113 } 114 115 /** 116 * Enable/disable motor safety for this device Turn on and off the motor safety option for this 117 * PWM object. 118 * 119 * @param enabled True if motor safety is enforced for this object 120 */ 121 public void setSafetyEnabled(boolean enabled) { 122 synchronized (m_thisMutex) { 123 m_enabled = enabled; 124 } 125 } 126 127 /** 128 * Return the state of the motor safety enabled flag Return if the motor safety is currently 129 * enabled for this device. 130 * 131 * @return True if motor safety is enforced for this device 132 */ 133 public boolean isSafetyEnabled() { 134 synchronized (m_thisMutex) { 135 return m_enabled; 136 } 137 } 138 139 /** 140 * Check the motors to see if any have timed out. This static method is called periodically to 141 * poll all the motors and stop any that have timed out. 142 */ 143 public static void checkMotors() { 144 synchronized (m_listMutex) { 145 for (MotorSafetyHelper elem : m_helperList) { 146 elem.check(); 147 } 148 } 149 } 150}