blob: 32de5caf68c2d18289f744a1d720b44d4371f3a0 [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#include "frc/PneumaticsControlModule.h"
6
7#include <hal/CTREPCM.h>
8#include <wpi/NullDeleter.h>
9#include <wpi/StackTrace.h>
10
11#include "frc/Compressor.h"
12#include "frc/DoubleSolenoid.h"
13#include "frc/Errors.h"
14#include "frc/SensorUtil.h"
15#include "frc/Solenoid.h"
16
17using namespace frc;
18
19wpi::mutex PneumaticsControlModule::m_handleLock;
20std::unique_ptr<
21 wpi::DenseMap<int, std::weak_ptr<PneumaticsControlModule::DataStore>>>
22 PneumaticsControlModule::m_handleMap = nullptr;
23
24// Always called under lock, so we can avoid the double lock from the magic
25// static
26std::weak_ptr<PneumaticsControlModule::DataStore>&
27PneumaticsControlModule::GetDataStore(int module) {
28 if (!m_handleMap) {
29 m_handleMap = std::make_unique<wpi::DenseMap<
30 int, std::weak_ptr<PneumaticsControlModule::DataStore>>>();
31 }
32 return (*m_handleMap)[module];
33}
34
35class PneumaticsControlModule::DataStore {
36 public:
37 explicit DataStore(int module, const char* stackTrace) {
38 int32_t status = 0;
39 HAL_CTREPCMHandle handle =
40 HAL_InitializeCTREPCM(module, stackTrace, &status);
41 FRC_CheckErrorStatus(status, "Module {}", module);
42 m_moduleObject = PneumaticsControlModule{handle, module};
43 m_moduleObject.m_dataStore =
44 std::shared_ptr<DataStore>{this, wpi::NullDeleter<DataStore>()};
45 }
46
47 ~DataStore() noexcept { HAL_FreeCTREPCM(m_moduleObject.m_handle); }
48
49 DataStore(DataStore&&) = delete;
50 DataStore& operator=(DataStore&&) = delete;
51
52 private:
53 friend class PneumaticsControlModule;
54 uint32_t m_reservedMask{0};
55 bool m_compressorReserved{false};
56 wpi::mutex m_reservedLock;
57 PneumaticsControlModule m_moduleObject{HAL_kInvalidHandle, 0};
58};
59
60PneumaticsControlModule::PneumaticsControlModule()
61 : PneumaticsControlModule{SensorUtil::GetDefaultCTREPCMModule()} {}
62
63PneumaticsControlModule::PneumaticsControlModule(int module) {
64 std::string stackTrace = wpi::GetStackTrace(1);
65 std::scoped_lock lock(m_handleLock);
66 auto& res = GetDataStore(module);
67 m_dataStore = res.lock();
68 if (!m_dataStore) {
69 m_dataStore = std::make_shared<DataStore>(module, stackTrace.c_str());
70 res = m_dataStore;
71 }
72 m_handle = m_dataStore->m_moduleObject.m_handle;
73 m_module = module;
74}
75
76PneumaticsControlModule::PneumaticsControlModule(HAL_CTREPCMHandle handle,
77 int module)
78 : m_handle{handle}, m_module{module} {}
79
80bool PneumaticsControlModule::GetCompressor() const {
81 int32_t status = 0;
82 auto result = HAL_GetCTREPCMCompressor(m_handle, &status);
83 FRC_CheckErrorStatus(status, "Module {}", m_module);
84 return result;
85}
86
87void PneumaticsControlModule::SetClosedLoopControl(bool enabled) {
88 int32_t status = 0;
89 HAL_SetCTREPCMClosedLoopControl(m_handle, enabled, &status);
90 FRC_CheckErrorStatus(status, "Module {}", m_module);
91}
92
93bool PneumaticsControlModule::GetClosedLoopControl() const {
94 int32_t status = 0;
95 auto result = HAL_GetCTREPCMClosedLoopControl(m_handle, &status);
96 FRC_CheckErrorStatus(status, "Module {}", m_module);
97 return result;
98}
99
100bool PneumaticsControlModule::GetPressureSwitch() const {
101 int32_t status = 0;
102 auto result = HAL_GetCTREPCMPressureSwitch(m_handle, &status);
103 FRC_CheckErrorStatus(status, "Module {}", m_module);
104 return result;
105}
106
107double PneumaticsControlModule::GetCompressorCurrent() const {
108 int32_t status = 0;
109 auto result = HAL_GetCTREPCMCompressorCurrent(m_handle, &status);
110 FRC_CheckErrorStatus(status, "Module {}", m_module);
111 return result;
112}
113
114bool PneumaticsControlModule::GetCompressorCurrentTooHighFault() const {
115 int32_t status = 0;
116 auto result = HAL_GetCTREPCMCompressorCurrentTooHighFault(m_handle, &status);
117 FRC_CheckErrorStatus(status, "Module {}", m_module);
118 return result;
119}
120bool PneumaticsControlModule::GetCompressorCurrentTooHighStickyFault() const {
121 int32_t status = 0;
122 auto result =
123 HAL_GetCTREPCMCompressorCurrentTooHighStickyFault(m_handle, &status);
124 FRC_CheckErrorStatus(status, "Module {}", m_module);
125 return result;
126}
127bool PneumaticsControlModule::GetCompressorShortedFault() const {
128 int32_t status = 0;
129 auto result = HAL_GetCTREPCMCompressorShortedFault(m_handle, &status);
130 FRC_CheckErrorStatus(status, "Module {}", m_module);
131 return result;
132}
133bool PneumaticsControlModule::GetCompressorShortedStickyFault() const {
134 int32_t status = 0;
135 auto result = HAL_GetCTREPCMCompressorShortedStickyFault(m_handle, &status);
136 FRC_CheckErrorStatus(status, "Module {}", m_module);
137 return result;
138}
139bool PneumaticsControlModule::GetCompressorNotConnectedFault() const {
140 int32_t status = 0;
141 auto result = HAL_GetCTREPCMCompressorNotConnectedFault(m_handle, &status);
142 FRC_CheckErrorStatus(status, "Module {}", m_module);
143 return result;
144}
145bool PneumaticsControlModule::GetCompressorNotConnectedStickyFault() const {
146 int32_t status = 0;
147 auto result =
148 HAL_GetCTREPCMCompressorNotConnectedStickyFault(m_handle, &status);
149 FRC_CheckErrorStatus(status, "Module {}", m_module);
150 return result;
151}
152
153bool PneumaticsControlModule::GetSolenoidVoltageFault() const {
154 int32_t status = 0;
155 auto result = HAL_GetCTREPCMSolenoidVoltageFault(m_handle, &status);
156 FRC_CheckErrorStatus(status, "Module {}", m_module);
157 return result;
158}
159bool PneumaticsControlModule::GetSolenoidVoltageStickyFault() const {
160 int32_t status = 0;
161 auto result = HAL_GetCTREPCMSolenoidVoltageStickyFault(m_handle, &status);
162 FRC_CheckErrorStatus(status, "Module {}", m_module);
163 return result;
164}
165
166void PneumaticsControlModule::ClearAllStickyFaults() {
167 int32_t status = 0;
168 HAL_ClearAllCTREPCMStickyFaults(m_handle, &status);
169 FRC_CheckErrorStatus(status, "Module {}", m_module);
170}
171
172void PneumaticsControlModule::SetSolenoids(int mask, int values) {
173 int32_t status = 0;
174 HAL_SetCTREPCMSolenoids(m_handle, mask, values, &status);
175 FRC_CheckErrorStatus(status, "Module {}", m_module);
176}
177
178int PneumaticsControlModule::GetSolenoids() const {
179 int32_t status = 0;
180 auto result = HAL_GetCTREPCMSolenoids(m_handle, &status);
181 FRC_CheckErrorStatus(status, "Module {}", m_module);
182 return result;
183}
184
185int PneumaticsControlModule::GetModuleNumber() const {
186 return m_module;
187}
188
189int PneumaticsControlModule::GetSolenoidDisabledList() const {
190 int32_t status = 0;
191 auto result = HAL_GetCTREPCMSolenoidDisabledList(m_handle, &status);
192 FRC_CheckErrorStatus(status, "Module {}", m_module);
193 return result;
194}
195
196void PneumaticsControlModule::FireOneShot(int index) {
197 int32_t status = 0;
198 HAL_FireCTREPCMOneShot(m_handle, index, &status);
199 FRC_CheckErrorStatus(status, "Module {}", m_module);
200}
201
202void PneumaticsControlModule::SetOneShotDuration(int index,
203 units::second_t duration) {
204 int32_t status = 0;
205 units::millisecond_t millis = duration;
206 HAL_SetCTREPCMOneShotDuration(m_handle, index, millis.to<int32_t>(), &status);
207 FRC_CheckErrorStatus(status, "Module {}", m_module);
208}
209
210bool PneumaticsControlModule::CheckSolenoidChannel(int channel) const {
211 return HAL_CheckCTREPCMSolenoidChannel(channel);
212}
213
214int PneumaticsControlModule::CheckAndReserveSolenoids(int mask) {
215 std::scoped_lock lock{m_dataStore->m_reservedLock};
216 uint32_t uMask = static_cast<uint32_t>(mask);
217 if ((m_dataStore->m_reservedMask & uMask) != 0) {
218 return m_dataStore->m_reservedMask & uMask;
219 }
220 m_dataStore->m_reservedMask |= uMask;
221 return 0;
222}
223
224void PneumaticsControlModule::UnreserveSolenoids(int mask) {
225 std::scoped_lock lock{m_dataStore->m_reservedLock};
226 m_dataStore->m_reservedMask &= ~(static_cast<uint32_t>(mask));
227}
228
229bool PneumaticsControlModule::ReserveCompressor() {
230 std::scoped_lock lock{m_dataStore->m_reservedLock};
231 if (m_dataStore->m_compressorReserved) {
232 return false;
233 }
234 m_dataStore->m_compressorReserved = true;
235 return true;
236}
237
238void PneumaticsControlModule::UnreserveCompressor() {
239 std::scoped_lock lock{m_dataStore->m_reservedLock};
240 m_dataStore->m_compressorReserved = false;
241}
242
243Solenoid PneumaticsControlModule::MakeSolenoid(int channel) {
244 return Solenoid{m_module, PneumaticsModuleType::CTREPCM, channel};
245}
246
247DoubleSolenoid PneumaticsControlModule::MakeDoubleSolenoid(int forwardChannel,
248 int reverseChannel) {
249 return DoubleSolenoid{m_module, PneumaticsModuleType::CTREPCM, forwardChannel,
250 reverseChannel};
251}
252
253Compressor PneumaticsControlModule::MakeCompressor() {
254 return Compressor{m_module, PneumaticsModuleType::CTREPCM};
255}
256
257std::shared_ptr<PneumaticsBase> PneumaticsControlModule::GetForModule(
258 int module) {
259 std::string stackTrace = wpi::GetStackTrace(1);
260 std::scoped_lock lock(m_handleLock);
261 auto& res = GetDataStore(module);
262 std::shared_ptr<DataStore> dataStore = res.lock();
263 if (!dataStore) {
264 dataStore = std::make_shared<DataStore>(module, stackTrace.c_str());
265 res = dataStore;
266 }
267
268 return std::shared_ptr<PneumaticsBase>{dataStore, &dataStore->m_moduleObject};
269}