blob: df4ecdead291aa0349d314dbb309c9ba8c1dbbb9 [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 *
52 * Resets the timer on this object that is used to do the timeouts.
53 */
54void MotorSafetyHelper::Feed() {
55 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
56 m_stopTime = Timer::GetFPGATimestamp() + m_expiration;
57}
58
59/**
60 * Set the expiration time for the corresponding motor safety object.
61 *
62 * @param expirationTime The timeout value in seconds.
63 */
64void MotorSafetyHelper::SetExpiration(double expirationTime) {
65 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
66 m_expiration = expirationTime;
67}
68
69/**
70 * Retrieve the timeout value for the corresponding motor safety object.
71 *
72 * @return the timeout value in seconds.
73 */
74double MotorSafetyHelper::GetExpiration() const {
75 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
76 return m_expiration;
77}
78
79/**
80 * Determine if the motor is still operating or has timed out.
81 *
82 * @return a true value if the motor is still operating normally and hasn't
83 * timed out.
84 */
85bool MotorSafetyHelper::IsAlive() const {
86 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
87 return !m_enabled || m_stopTime > Timer::GetFPGATimestamp();
88}
89
90/**
91 * Check if this motor has exceeded its timeout.
92 *
93 * This method is called periodically to determine if this motor has exceeded
94 * its timeout value. If it has, the stop method is called, and the motor is
95 * shut down until its value is updated again.
96 */
97void MotorSafetyHelper::Check() {
98 DriverStation& ds = DriverStation::GetInstance();
99 if (!m_enabled || ds.IsDisabled() || ds.IsTest()) return;
100
101 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
102 if (m_stopTime < Timer::GetFPGATimestamp()) {
103 std::ostringstream desc;
104 m_safeObject->GetDescription(desc);
105 desc << "... Output not updated often enough.";
106 wpi_setWPIErrorWithContext(Timeout, desc.str().c_str());
107 m_safeObject->StopMotor();
108 }
109}
110
111/**
112 * Enable/disable motor safety for this device.
113 *
114 * Turn on and off the motor safety option for this PWM object.
115 *
116 * @param enabled True if motor safety is enforced for this object
117 */
118void MotorSafetyHelper::SetSafetyEnabled(bool enabled) {
119 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
120 m_enabled = enabled;
121}
122
123/**
124 * Return the state of the motor safety enabled flag.
125 *
126 * Return if the motor safety is currently enabled for this devicce.
127 *
128 * @return True if motor safety is enforced for this device
129 */
130bool MotorSafetyHelper::IsSafetyEnabled() const {
131 std::lock_guard<priority_recursive_mutex> sync(m_syncMutex);
132 return m_enabled;
133}
134
135/**
136 * Check the motors to see if any have timed out.
137 *
138 * This static method is called periodically to poll all the motors and stop
139 * any that have timed out.
140 */
141void MotorSafetyHelper::CheckMotors() {
142 std::lock_guard<priority_recursive_mutex> sync(m_listMutex);
143 for (auto elem : m_helperList) {
144 elem->Check();
145 }
146}