blob: a1d85bc8db4a16fd2b70199c876adb16850482f4 [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2016-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 "HAL/AnalogTrigger.h"
9
10#include "AnalogInternal.h"
11#include "HAL/AnalogInput.h"
12#include "HAL/Errors.h"
13#include "HAL/handles/HandlesInternal.h"
14#include "HAL/handles/LimitedHandleResource.h"
15#include "PortsInternal.h"
16
17using namespace hal;
18
19namespace {
20struct AnalogTrigger {
21 std::unique_ptr<tAnalogTrigger> trigger;
22 HAL_AnalogInputHandle analogHandle;
23 uint8_t index;
24};
25}
26
27static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
28 kNumAnalogTriggers, HAL_HandleEnum::AnalogTrigger>
29 analogTriggerHandles;
30
31extern "C" {
32
33HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
34 HAL_AnalogInputHandle portHandle, int32_t* index, int32_t* status) {
35 // ensure we are given a valid and active AnalogInput handle
36 auto analog_port = analogInputHandles.Get(portHandle);
37 if (analog_port == nullptr) {
38 *status = HAL_HANDLE_ERROR;
39 return HAL_kInvalidHandle;
40 }
41 HAL_AnalogTriggerHandle handle = analogTriggerHandles.Allocate();
42 if (handle == HAL_kInvalidHandle) {
43 *status = NO_AVAILABLE_RESOURCES;
44 return HAL_kInvalidHandle;
45 }
46 auto trigger = analogTriggerHandles.Get(handle);
47 if (trigger == nullptr) { // would only occur on thread issue
48 *status = HAL_HANDLE_ERROR;
49 return HAL_kInvalidHandle;
50 }
51 trigger->analogHandle = portHandle;
52 trigger->index = static_cast<uint8_t>(getHandleIndex(handle));
53 *index = trigger->index;
54
55 trigger->trigger.reset(tAnalogTrigger::create(trigger->index, status));
56 trigger->trigger->writeSourceSelect_Channel(analog_port->channel, status);
57 return handle;
58}
59
60void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
61 int32_t* status) {
62 analogTriggerHandles.Free(analogTriggerHandle);
63 // caller owns the analog input handle.
64}
65
66void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
67 int32_t lower, int32_t upper,
68 int32_t* status) {
69 auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
70 if (trigger == nullptr) {
71 *status = HAL_HANDLE_ERROR;
72 return;
73 }
74 if (lower > upper) {
75 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
76 }
77 trigger->trigger->writeLowerLimit(lower, status);
78 trigger->trigger->writeUpperLimit(upper, status);
79}
80
81/**
82 * Set the upper and lower limits of the analog trigger.
83 * The limits are given as floating point voltage values.
84 */
85void HAL_SetAnalogTriggerLimitsVoltage(
86 HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
87 int32_t* status) {
88 auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
89 if (trigger == nullptr) {
90 *status = HAL_HANDLE_ERROR;
91 return;
92 }
93 if (lower > upper) {
94 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
95 }
96
97 // TODO: This depends on the averaged setting. Only raw values will work as
98 // is.
99 trigger->trigger->writeLowerLimit(
100 HAL_GetAnalogVoltsToValue(trigger->analogHandle, lower, status), status);
101 trigger->trigger->writeUpperLimit(
102 HAL_GetAnalogVoltsToValue(trigger->analogHandle, upper, status), status);
103}
104
105/**
106 * Configure the analog trigger to use the averaged vs. raw values.
107 * If the value is true, then the averaged value is selected for the analog
108 * trigger, otherwise the immediate value is used.
109 */
110void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
111 HAL_Bool useAveragedValue, int32_t* status) {
112 auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
113 if (trigger == nullptr) {
114 *status = HAL_HANDLE_ERROR;
115 return;
116 }
117 if (trigger->trigger->readSourceSelect_Filter(status) != 0) {
118 *status = INCOMPATIBLE_STATE;
119 // TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not
120 // support average and filtering at the same time.");
121 }
122 trigger->trigger->writeSourceSelect_Averaged(useAveragedValue, status);
123}
124
125/**
126 * Configure the analog trigger to use a filtered value.
127 * The analog trigger will operate with a 3 point average rejection filter. This
128 * is designed to help with 360 degree pot applications for the period where the
129 * pot crosses through zero.
130 */
131void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
132 HAL_Bool useFilteredValue, int32_t* status) {
133 auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
134 if (trigger == nullptr) {
135 *status = HAL_HANDLE_ERROR;
136 return;
137 }
138 if (trigger->trigger->readSourceSelect_Averaged(status) != 0) {
139 *status = INCOMPATIBLE_STATE;
140 // TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not "
141 // "support average and filtering at the same time.");
142 }
143 trigger->trigger->writeSourceSelect_Filter(useFilteredValue, status);
144}
145
146/**
147 * Return the InWindow output of the analog trigger.
148 * True if the analog input is between the upper and lower limits.
149 * @return The InWindow output of the analog trigger.
150 */
151HAL_Bool HAL_GetAnalogTriggerInWindow(
152 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
153 auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
154 if (trigger == nullptr) {
155 *status = HAL_HANDLE_ERROR;
156 return false;
157 }
158 return trigger->trigger->readOutput_InHysteresis(trigger->index, status) != 0;
159}
160
161/**
162 * Return the TriggerState output of the analog trigger.
163 * True if above upper limit.
164 * False if below lower limit.
165 * If in Hysteresis, maintain previous state.
166 * @return The TriggerState output of the analog trigger.
167 */
168HAL_Bool HAL_GetAnalogTriggerTriggerState(
169 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
170 auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
171 if (trigger == nullptr) {
172 *status = HAL_HANDLE_ERROR;
173 return false;
174 }
175 return trigger->trigger->readOutput_OverLimit(trigger->index, status) != 0;
176}
177
178/**
179 * Get the state of the analog trigger output.
180 * @return The state of the analog trigger output.
181 */
182HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
183 HAL_AnalogTriggerType type,
184 int32_t* status) {
185 auto trigger = analogTriggerHandles.Get(analogTriggerHandle);
186 if (trigger == nullptr) {
187 *status = HAL_HANDLE_ERROR;
188 return false;
189 }
190 bool result = false;
191 switch (type) {
192 case HAL_Trigger_kInWindow:
193 result =
194 trigger->trigger->readOutput_InHysteresis(trigger->index, status);
195 break; // XXX: Backport
196 case HAL_Trigger_kState:
197 result = trigger->trigger->readOutput_OverLimit(trigger->index, status);
198 break; // XXX: Backport
199 case HAL_Trigger_kRisingPulse:
200 case HAL_Trigger_kFallingPulse:
201 *status = ANALOG_TRIGGER_PULSE_OUTPUT_ERROR;
202 return false;
203 }
204 return result;
205}
206}