blob: 77e7a2a99e7238abc223424487699facaba0fbdb [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2008-2018 FIRST. 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 "frc/Encoder.h"
9
10#include <utility>
11
12#include <hal/Encoder.h>
13#include <hal/FRCUsageReporting.h>
14#include <hal/HALBase.h>
15
16#include "frc/DigitalInput.h"
17#include "frc/WPIErrors.h"
18#include "frc/smartdashboard/SendableBuilder.h"
19
20using namespace frc;
21
22Encoder::Encoder(int aChannel, int bChannel, bool reverseDirection,
23 EncodingType encodingType) {
24 m_aSource = std::make_shared<DigitalInput>(aChannel);
25 m_bSource = std::make_shared<DigitalInput>(bChannel);
26 InitEncoder(reverseDirection, encodingType);
27 AddChild(m_aSource);
28 AddChild(m_bSource);
29}
30
31Encoder::Encoder(DigitalSource* aSource, DigitalSource* bSource,
32 bool reverseDirection, EncodingType encodingType)
33 : m_aSource(aSource, NullDeleter<DigitalSource>()),
34 m_bSource(bSource, NullDeleter<DigitalSource>()) {
35 if (m_aSource == nullptr || m_bSource == nullptr)
36 wpi_setWPIError(NullParameter);
37 else
38 InitEncoder(reverseDirection, encodingType);
39}
40
41Encoder::Encoder(DigitalSource& aSource, DigitalSource& bSource,
42 bool reverseDirection, EncodingType encodingType)
43 : m_aSource(&aSource, NullDeleter<DigitalSource>()),
44 m_bSource(&bSource, NullDeleter<DigitalSource>()) {
45 InitEncoder(reverseDirection, encodingType);
46}
47
48Encoder::Encoder(std::shared_ptr<DigitalSource> aSource,
49 std::shared_ptr<DigitalSource> bSource, bool reverseDirection,
50 EncodingType encodingType)
51 : m_aSource(aSource), m_bSource(bSource) {
52 if (m_aSource == nullptr || m_bSource == nullptr)
53 wpi_setWPIError(NullParameter);
54 else
55 InitEncoder(reverseDirection, encodingType);
56}
57
58Encoder::~Encoder() {
59 int32_t status = 0;
60 HAL_FreeEncoder(m_encoder, &status);
61 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
62}
63
64Encoder::Encoder(Encoder&& rhs)
65 : ErrorBase(std::move(rhs)),
66 SendableBase(std::move(rhs)),
67 CounterBase(std::move(rhs)),
68 PIDSource(std::move(rhs)),
69 m_aSource(std::move(rhs.m_aSource)),
70 m_bSource(std::move(rhs.m_bSource)),
71 m_indexSource(std::move(rhs.m_indexSource)) {
72 std::swap(m_encoder, rhs.m_encoder);
73}
74
75Encoder& Encoder::operator=(Encoder&& rhs) {
76 ErrorBase::operator=(std::move(rhs));
77 SendableBase::operator=(std::move(rhs));
78 CounterBase::operator=(std::move(rhs));
79 PIDSource::operator=(std::move(rhs));
80
81 m_aSource = std::move(rhs.m_aSource);
82 m_bSource = std::move(rhs.m_bSource);
83 m_indexSource = std::move(rhs.m_indexSource);
84 std::swap(m_encoder, rhs.m_encoder);
85
86 return *this;
87}
88
89int Encoder::Get() const {
90 if (StatusIsFatal()) return 0;
91 int32_t status = 0;
92 int value = HAL_GetEncoder(m_encoder, &status);
93 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
94 return value;
95}
96
97void Encoder::Reset() {
98 if (StatusIsFatal()) return;
99 int32_t status = 0;
100 HAL_ResetEncoder(m_encoder, &status);
101 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
102}
103
104double Encoder::GetPeriod() const {
105 if (StatusIsFatal()) return 0.0;
106 int32_t status = 0;
107 double value = HAL_GetEncoderPeriod(m_encoder, &status);
108 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
109 return value;
110}
111
112void Encoder::SetMaxPeriod(double maxPeriod) {
113 if (StatusIsFatal()) return;
114 int32_t status = 0;
115 HAL_SetEncoderMaxPeriod(m_encoder, maxPeriod, &status);
116 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
117}
118
119bool Encoder::GetStopped() const {
120 if (StatusIsFatal()) return true;
121 int32_t status = 0;
122 bool value = HAL_GetEncoderStopped(m_encoder, &status);
123 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
124 return value;
125}
126
127bool Encoder::GetDirection() const {
128 if (StatusIsFatal()) return false;
129 int32_t status = 0;
130 bool value = HAL_GetEncoderDirection(m_encoder, &status);
131 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
132 return value;
133}
134
135int Encoder::GetRaw() const {
136 if (StatusIsFatal()) return 0;
137 int32_t status = 0;
138 int value = HAL_GetEncoderRaw(m_encoder, &status);
139 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
140 return value;
141}
142
143int Encoder::GetEncodingScale() const {
144 int32_t status = 0;
145 int val = HAL_GetEncoderEncodingScale(m_encoder, &status);
146 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
147 return val;
148}
149
150double Encoder::GetDistance() const {
151 if (StatusIsFatal()) return 0.0;
152 int32_t status = 0;
153 double value = HAL_GetEncoderDistance(m_encoder, &status);
154 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
155 return value;
156}
157
158double Encoder::GetRate() const {
159 if (StatusIsFatal()) return 0.0;
160 int32_t status = 0;
161 double value = HAL_GetEncoderRate(m_encoder, &status);
162 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
163 return value;
164}
165
166void Encoder::SetMinRate(double minRate) {
167 if (StatusIsFatal()) return;
168 int32_t status = 0;
169 HAL_SetEncoderMinRate(m_encoder, minRate, &status);
170 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
171}
172
173void Encoder::SetDistancePerPulse(double distancePerPulse) {
174 if (StatusIsFatal()) return;
175 int32_t status = 0;
176 HAL_SetEncoderDistancePerPulse(m_encoder, distancePerPulse, &status);
177 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
178}
179
180double Encoder::GetDistancePerPulse() const {
181 if (StatusIsFatal()) return 0.0;
182 int32_t status = 0;
183 double distancePerPulse = HAL_GetEncoderDistancePerPulse(m_encoder, &status);
184 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
185 return distancePerPulse;
186}
187
188void Encoder::SetReverseDirection(bool reverseDirection) {
189 if (StatusIsFatal()) return;
190 int32_t status = 0;
191 HAL_SetEncoderReverseDirection(m_encoder, reverseDirection, &status);
192 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
193}
194
195void Encoder::SetSamplesToAverage(int samplesToAverage) {
196 if (samplesToAverage < 1 || samplesToAverage > 127) {
197 wpi_setWPIErrorWithContext(
198 ParameterOutOfRange,
199 "Average counter values must be between 1 and 127");
200 return;
201 }
202 int32_t status = 0;
203 HAL_SetEncoderSamplesToAverage(m_encoder, samplesToAverage, &status);
204 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
205}
206
207int Encoder::GetSamplesToAverage() const {
208 int32_t status = 0;
209 int result = HAL_GetEncoderSamplesToAverage(m_encoder, &status);
210 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
211 return result;
212}
213
214double Encoder::PIDGet() {
215 if (StatusIsFatal()) return 0.0;
216 switch (GetPIDSourceType()) {
217 case PIDSourceType::kDisplacement:
218 return GetDistance();
219 case PIDSourceType::kRate:
220 return GetRate();
221 default:
222 return 0.0;
223 }
224}
225
226void Encoder::SetIndexSource(int channel, Encoder::IndexingType type) {
227 // Force digital input if just given an index
228 m_indexSource = std::make_shared<DigitalInput>(channel);
229 AddChild(m_indexSource);
230 SetIndexSource(*m_indexSource.get(), type);
231}
232
233void Encoder::SetIndexSource(const DigitalSource& source,
234 Encoder::IndexingType type) {
235 int32_t status = 0;
236 HAL_SetEncoderIndexSource(
237 m_encoder, source.GetPortHandleForRouting(),
238 (HAL_AnalogTriggerType)source.GetAnalogTriggerTypeForRouting(),
239 (HAL_EncoderIndexingType)type, &status);
240 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
241}
242
243int Encoder::GetFPGAIndex() const {
244 int32_t status = 0;
245 int val = HAL_GetEncoderFPGAIndex(m_encoder, &status);
246 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
247 return val;
248}
249
250void Encoder::InitSendable(SendableBuilder& builder) {
251 int32_t status = 0;
252 HAL_EncoderEncodingType type = HAL_GetEncoderEncodingType(m_encoder, &status);
253 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
254 if (type == HAL_EncoderEncodingType::HAL_Encoder_k4X)
255 builder.SetSmartDashboardType("Quadrature Encoder");
256 else
257 builder.SetSmartDashboardType("Encoder");
258
259 builder.AddDoubleProperty("Speed", [=]() { return GetRate(); }, nullptr);
260 builder.AddDoubleProperty("Distance", [=]() { return GetDistance(); },
261 nullptr);
262 builder.AddDoubleProperty("Distance per Tick",
263 [=]() { return GetDistancePerPulse(); }, nullptr);
264}
265
266void Encoder::InitEncoder(bool reverseDirection, EncodingType encodingType) {
267 int32_t status = 0;
268 m_encoder = HAL_InitializeEncoder(
269 m_aSource->GetPortHandleForRouting(),
270 (HAL_AnalogTriggerType)m_aSource->GetAnalogTriggerTypeForRouting(),
271 m_bSource->GetPortHandleForRouting(),
272 (HAL_AnalogTriggerType)m_bSource->GetAnalogTriggerTypeForRouting(),
273 reverseDirection, (HAL_EncoderEncodingType)encodingType, &status);
274 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
275
276 HAL_Report(HALUsageReporting::kResourceType_Encoder, GetFPGAIndex(),
277 encodingType);
278 SetName("Encoder", m_aSource->GetChannel());
279}
280
281double Encoder::DecodingScaleFactor() const {
282 if (StatusIsFatal()) return 0.0;
283 int32_t status = 0;
284 double val = HAL_GetEncoderDecodingScaleFactor(m_encoder, &status);
285 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
286 return val;
287}