blob: 8e994e9baa154c79c5bbda485f1ad1c086324aad [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.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "frc/DutyCycleEncoder.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <wpi/NullDeleter.h>
8#include <wpi/sendable/SendableBuilder.h>
9
Brian Silverman8fce7482020-01-05 13:18:21 -080010#include "frc/Counter.h"
11#include "frc/DigitalInput.h"
12#include "frc/DigitalSource.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080013#include "frc/DutyCycle.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070014#include "frc/Errors.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080015
16using namespace frc;
17
18DutyCycleEncoder::DutyCycleEncoder(int channel)
19 : m_dutyCycle{std::make_shared<DutyCycle>(
Austin Schuh1e69f942020-11-14 15:06:14 -080020 std::make_shared<DigitalInput>(channel))} {
Brian Silverman8fce7482020-01-05 13:18:21 -080021 Init();
22}
23
24DutyCycleEncoder::DutyCycleEncoder(DutyCycle& dutyCycle)
Austin Schuh812d0d12021-11-04 20:16:48 -070025 : m_dutyCycle{&dutyCycle, wpi::NullDeleter<DutyCycle>{}} {
Brian Silverman8fce7482020-01-05 13:18:21 -080026 Init();
27}
28
29DutyCycleEncoder::DutyCycleEncoder(DutyCycle* dutyCycle)
Austin Schuh812d0d12021-11-04 20:16:48 -070030 : m_dutyCycle{dutyCycle, wpi::NullDeleter<DutyCycle>{}} {
Brian Silverman8fce7482020-01-05 13:18:21 -080031 Init();
32}
33
34DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DutyCycle> dutyCycle)
Austin Schuh1e69f942020-11-14 15:06:14 -080035 : m_dutyCycle{std::move(dutyCycle)} {
Brian Silverman8fce7482020-01-05 13:18:21 -080036 Init();
37}
38
39DutyCycleEncoder::DutyCycleEncoder(DigitalSource& digitalSource)
Austin Schuh1e69f942020-11-14 15:06:14 -080040 : m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Brian Silverman8fce7482020-01-05 13:18:21 -080041 Init();
42}
43
44DutyCycleEncoder::DutyCycleEncoder(DigitalSource* digitalSource)
Austin Schuh1e69f942020-11-14 15:06:14 -080045 : m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Brian Silverman8fce7482020-01-05 13:18:21 -080046 Init();
47}
48
49DutyCycleEncoder::DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource)
Austin Schuh1e69f942020-11-14 15:06:14 -080050 : m_dutyCycle{std::make_shared<DutyCycle>(digitalSource)} {
Brian Silverman8fce7482020-01-05 13:18:21 -080051 Init();
52}
53
54void DutyCycleEncoder::Init() {
Austin Schuh812d0d12021-11-04 20:16:48 -070055 m_simDevice = hal::SimDevice{"DutyCycle:DutyCycleEncoder",
56 m_dutyCycle->GetSourceChannel()};
Brian Silverman8fce7482020-01-05 13:18:21 -080057
58 if (m_simDevice) {
Austin Schuh812d0d12021-11-04 20:16:48 -070059 m_simPosition =
60 m_simDevice.CreateDouble("position", hal::SimDevice::kInput, 0.0);
61 m_simDistancePerRotation = m_simDevice.CreateDouble(
62 "distance_per_rot", hal::SimDevice::kOutput, 1.0);
63 m_simIsConnected =
64 m_simDevice.CreateBoolean("connected", hal::SimDevice::kInput, true);
Austin Schuh1e69f942020-11-14 15:06:14 -080065 } else {
66 m_analogTrigger = std::make_unique<AnalogTrigger>(m_dutyCycle.get());
67 m_analogTrigger->SetLimitsDutyCycle(0.25, 0.75);
68 m_counter = std::make_unique<Counter>();
69 m_counter->SetUpSource(
70 m_analogTrigger->CreateOutput(AnalogTriggerType::kRisingPulse));
71 m_counter->SetDownSource(
72 m_analogTrigger->CreateOutput(AnalogTriggerType::kFallingPulse));
Brian Silverman8fce7482020-01-05 13:18:21 -080073 }
74
Austin Schuh812d0d12021-11-04 20:16:48 -070075 wpi::SendableRegistry::AddLW(this, "DutyCycle Encoder",
76 m_dutyCycle->GetSourceChannel());
Brian Silverman8fce7482020-01-05 13:18:21 -080077}
78
79units::turn_t DutyCycleEncoder::Get() const {
Austin Schuh812d0d12021-11-04 20:16:48 -070080 if (m_simPosition) {
81 return units::turn_t{m_simPosition.Get()};
82 }
Brian Silverman8fce7482020-01-05 13:18:21 -080083
84 // As the values are not atomic, keep trying until we get 2 reads of the same
85 // value If we don't within 10 attempts, error
86 for (int i = 0; i < 10; i++) {
Austin Schuh1e69f942020-11-14 15:06:14 -080087 auto counter = m_counter->Get();
Brian Silverman8fce7482020-01-05 13:18:21 -080088 auto pos = m_dutyCycle->GetOutput();
Austin Schuh1e69f942020-11-14 15:06:14 -080089 auto counter2 = m_counter->Get();
Brian Silverman8fce7482020-01-05 13:18:21 -080090 auto pos2 = m_dutyCycle->GetOutput();
91 if (counter == counter2 && pos == pos2) {
92 units::turn_t turns{counter + pos - m_positionOffset};
93 m_lastPosition = turns;
94 return turns;
95 }
96 }
97
Austin Schuh812d0d12021-11-04 20:16:48 -070098 FRC_ReportError(
99 warn::Warning, "{}",
Brian Silverman8fce7482020-01-05 13:18:21 -0800100 "Failed to read DutyCycle Encoder. Potential Speed Overrun. Returning "
101 "last value");
102 return m_lastPosition;
103}
104
105void DutyCycleEncoder::SetDistancePerRotation(double distancePerRotation) {
106 m_distancePerRotation = distancePerRotation;
Austin Schuh1e69f942020-11-14 15:06:14 -0800107 m_simDistancePerRotation.Set(distancePerRotation);
Brian Silverman8fce7482020-01-05 13:18:21 -0800108}
109
110double DutyCycleEncoder::GetDistancePerRotation() const {
111 return m_distancePerRotation;
112}
113
114double DutyCycleEncoder::GetDistance() const {
Austin Schuh812d0d12021-11-04 20:16:48 -0700115 return Get().value() * GetDistancePerRotation();
Brian Silverman8fce7482020-01-05 13:18:21 -0800116}
117
118int DutyCycleEncoder::GetFrequency() const {
119 return m_dutyCycle->GetFrequency();
120}
121
122void DutyCycleEncoder::Reset() {
Austin Schuh812d0d12021-11-04 20:16:48 -0700123 if (m_counter) {
124 m_counter->Reset();
125 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800126 m_positionOffset = m_dutyCycle->GetOutput();
127}
128
129bool DutyCycleEncoder::IsConnected() const {
Austin Schuh812d0d12021-11-04 20:16:48 -0700130 if (m_simIsConnected) {
131 return m_simIsConnected.Get();
132 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800133 return GetFrequency() > m_frequencyThreshold;
134}
135
136void DutyCycleEncoder::SetConnectedFrequencyThreshold(int frequency) {
137 if (frequency < 0) {
138 frequency = 0;
139 }
140 m_frequencyThreshold = frequency;
141}
142
Austin Schuh1e69f942020-11-14 15:06:14 -0800143int DutyCycleEncoder::GetFPGAIndex() const {
144 return m_dutyCycle->GetFPGAIndex();
145}
146
147int DutyCycleEncoder::GetSourceChannel() const {
148 return m_dutyCycle->GetSourceChannel();
149}
150
Austin Schuh812d0d12021-11-04 20:16:48 -0700151void DutyCycleEncoder::InitSendable(wpi::SendableBuilder& builder) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800152 builder.SetSmartDashboardType("AbsoluteEncoder");
Austin Schuh1e69f942020-11-14 15:06:14 -0800153 builder.AddDoubleProperty(
154 "Distance", [this] { return this->GetDistance(); }, nullptr);
155 builder.AddDoubleProperty(
156 "Distance Per Rotation",
157 [this] { return this->GetDistancePerRotation(); }, nullptr);
158 builder.AddDoubleProperty(
159 "Is Connected", [this] { return this->IsConnected(); }, nullptr);
Brian Silverman8fce7482020-01-05 13:18:21 -0800160}