blob: 9f1ee89471b0e610ed0ae858a9c5fe4644820b63 [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008-2017. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "MotorSafetyHelper.h"
9
10#include <sstream>
11
12#include "DriverStation.h"
13#include "MotorSafety.h"
14#include "Timer.h"
15#include "WPIErrors.h"
16
17using namespace frc;
18
19std::set<MotorSafetyHelper*> MotorSafetyHelper::m_helperList;
20priority_recursive_mutex MotorSafetyHelper::m_listMutex;
21
22/**
23 * The constructor for a MotorSafetyHelper object.
24 *
25 * The helper object is constructed for every object that wants to implement the
26 * Motor Safety protocol. The helper object has the code to actually do the
27 * timing and call the motors Stop() method when the timeout expires. The motor
28 * object is expected to call the Feed() method whenever the motors value is
29 * updated.
30 *
31 * @param safeObject a pointer to the motor object implementing MotorSafety.
32 * This is used to call the Stop() method on the motor.
33 */
34MotorSafetyHelper::MotorSafetyHelper(MotorSafety* safeObject)
35 : m_safeObject(safeObject) {
36 m_enabled = false;
37 m_expiration = DEFAULT_SAFETY_EXPIRATION;
38 m_stopTime = Timer::GetFPGATimestamp();
39
40 std::lock_guard<priority_recursive_mutex> sync(m_listMutex);
41 m_helperList.insert(this);
42}
43
44MotorSafetyHelper::~MotorSafetyHelper() {
45 std::lock_guard<priority_recursive_mutex> sync(m_listMutex);
46 m_helperList.erase(this);
47}
48
49/**
50 * Feed the motor safety object.
51 * Resets the timer on this object that is used to do the timeouts.
52 */
53void MotorSafetyHelper::Feed() {
54 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
55 m_stopTime = Timer::GetFPGATimestamp() + m_expiration;
56}
57
58/**
59 * Set the expiration time for the corresponding motor safety object.
60 * @param expirationTime The timeout value in seconds.
61 */
62void MotorSafetyHelper::SetExpiration(double expirationTime) {
63 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
64 m_expiration = expirationTime;
65}
66
67/**
68 * Retrieve the timeout value for the corresponding motor safety object.
69 * @return the timeout value in seconds.
70 */
71double MotorSafetyHelper::GetExpiration() const {
72 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
73 return m_expiration;
74}
75
76/**
77 * Determine if the motor is still operating or has timed out.
78 * @return a true value if the motor is still operating normally and hasn't
79 * timed out.
80 */
81bool MotorSafetyHelper::IsAlive() const {
82 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
83 return !m_enabled || m_stopTime > Timer::GetFPGATimestamp();
84}
85
86/**
87 * Check if this motor has exceeded its timeout.
88 * This method is called periodically to determine if this motor has exceeded
89 * its timeout value. If it has, the stop method is called, and the motor is
90 * shut down until its value is updated again.
91 */
92void MotorSafetyHelper::Check() {
93 DriverStation& ds = DriverStation::GetInstance();
94 if (!m_enabled || ds.IsDisabled() || ds.IsTest()) return;
95
96 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
97 if (m_stopTime < Timer::GetFPGATimestamp()) {
98 std::ostringstream desc;
99 m_safeObject->GetDescription(desc);
100 desc << "... Output not updated often enough.";
101 wpi_setWPIErrorWithContext(Timeout, desc.str().c_str());
102 m_safeObject->StopMotor();
103 }
104}
105
106/**
107 * Enable/disable motor safety for this device
108 * Turn on and off the motor safety option for this PWM object.
109 * @param enabled True if motor safety is enforced for this object
110 */
111void MotorSafetyHelper::SetSafetyEnabled(bool enabled) {
112 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
113 m_enabled = enabled;
114}
115
116/**
117 * Return the state of the motor safety enabled flag
118 * Return if the motor safety is currently enabled for this devicce.
119 * @return True if motor safety is enforced for this device
120 */
121bool MotorSafetyHelper::IsSafetyEnabled() const {
122 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
123 return m_enabled;
124}
125
126/**
127 * Check the motors to see if any have timed out.
128 * This static method is called periodically to poll all the motors and stop
129 * any that have timed out.
130 */
131void MotorSafetyHelper::CheckMotors() {
132 std::lock_guard<priority_recursive_mutex> sync(m_listMutex);
133 for (auto elem : m_helperList) {
134 elem->Check();
135 }
136}