blob: 9ec3f29e3da34b8962f01e25f10fdcc3510f19ec [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2016-2019 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 "hal/AnalogTrigger.h"
9
10#include "AnalogInternal.h"
11#include "DutyCycleInternal.h"
12#include "HALInitializer.h"
13#include "PortsInternal.h"
14#include "hal/AnalogInput.h"
15#include "hal/DutyCycle.h"
16#include "hal/Errors.h"
17#include "hal/handles/HandlesInternal.h"
18#include "hal/handles/LimitedHandleResource.h"
19
20using namespace hal;
21
22namespace {
23
24struct AnalogTrigger {
25 std::unique_ptr<tAnalogTrigger> trigger;
26 HAL_Handle handle;
27 uint8_t index;
28};
29
30} // namespace
31
32static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
33 kNumAnalogTriggers, HAL_HandleEnum::AnalogTrigger>*
34 analogTriggerHandles;
35
36namespace hal {
37namespace init {
38void InitializeAnalogTrigger() {
39 static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
40 kNumAnalogTriggers,
41 HAL_HandleEnum::AnalogTrigger>
42 atH;
43 analogTriggerHandles = &atH;
44}
45} // namespace init
46} // namespace hal
47
48extern "C" {
49
50HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
51 HAL_AnalogInputHandle portHandle, int32_t* status) {
52 hal::init::CheckInit();
53 // ensure we are given a valid and active AnalogInput handle
54 auto analog_port = analogInputHandles->Get(portHandle);
55 if (analog_port == nullptr) {
56 *status = HAL_HANDLE_ERROR;
57 return HAL_kInvalidHandle;
58 }
59 HAL_AnalogTriggerHandle handle = analogTriggerHandles->Allocate();
60 if (handle == HAL_kInvalidHandle) {
61 *status = NO_AVAILABLE_RESOURCES;
62 return HAL_kInvalidHandle;
63 }
64 auto trigger = analogTriggerHandles->Get(handle);
65 if (trigger == nullptr) { // would only occur on thread issue
66 *status = HAL_HANDLE_ERROR;
67 return HAL_kInvalidHandle;
68 }
69 trigger->handle = portHandle;
70 trigger->index = static_cast<uint8_t>(getHandleIndex(handle));
71
72 trigger->trigger.reset(tAnalogTrigger::create(trigger->index, status));
73 trigger->trigger->writeSourceSelect_Channel(analog_port->channel, status);
74 return handle;
75}
76
77HAL_AnalogTriggerHandle HAL_InitializeAnalogTriggerDutyCycle(
78 HAL_DutyCycleHandle dutyCycleHandle, int32_t* status) {
79 hal::init::CheckInit();
80 // ensure we are given a valid and active DutyCycle handle
81 auto dutyCycle = dutyCycleHandles->Get(dutyCycleHandle);
82 if (dutyCycle == nullptr) {
83 *status = HAL_HANDLE_ERROR;
84 return HAL_kInvalidHandle;
85 }
86 HAL_AnalogTriggerHandle handle = analogTriggerHandles->Allocate();
87 if (handle == HAL_kInvalidHandle) {
88 *status = NO_AVAILABLE_RESOURCES;
89 return HAL_kInvalidHandle;
90 }
91 auto trigger = analogTriggerHandles->Get(handle);
92 if (trigger == nullptr) { // would only occur on thread issue
93 *status = HAL_HANDLE_ERROR;
94 return HAL_kInvalidHandle;
95 }
96 trigger->handle = dutyCycleHandle;
97 trigger->index = static_cast<uint8_t>(getHandleIndex(handle));
98
99 trigger->trigger.reset(tAnalogTrigger::create(trigger->index, status));
100 trigger->trigger->writeSourceSelect_Channel(dutyCycle->index, status);
101 trigger->trigger->writeSourceSelect_DutyCycle(true, status);
102 return handle;
103}
104
105void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
106 int32_t* status) {
107 analogTriggerHandles->Free(analogTriggerHandle);
108 // caller owns the input handle.
109}
110
111void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
112 int32_t lower, int32_t upper,
113 int32_t* status) {
114 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
115 if (trigger == nullptr) {
116 *status = HAL_HANDLE_ERROR;
117 return;
118 }
119 if (lower > upper) {
120 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
121 return;
122 }
123 trigger->trigger->writeLowerLimit(lower, status);
124 trigger->trigger->writeUpperLimit(upper, status);
125}
126
127void HAL_SetAnalogTriggerLimitsDutyCycle(
128 HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
129 int32_t* status) {
130 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
131 if (trigger == nullptr) {
132 *status = HAL_HANDLE_ERROR;
133 return;
134 }
135 if (getHandleType(trigger->handle) != HAL_HandleEnum::DutyCycle) {
136 *status = HAL_HANDLE_ERROR;
137 return;
138 }
139 if (lower > upper) {
140 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
141 return;
142 }
143
144 if (lower < 0.0 || upper > 1.0) {
145 *status = PARAMETER_OUT_OF_RANGE;
146 return;
147 }
148
149 int32_t scaleFactor =
150 HAL_GetDutyCycleOutputScaleFactor(trigger->handle, status);
151 if (*status != 0) {
152 return;
153 }
154
155 trigger->trigger->writeLowerLimit(static_cast<int32_t>(scaleFactor * lower),
156 status);
157 trigger->trigger->writeUpperLimit(static_cast<int32_t>(scaleFactor * upper),
158 status);
159}
160
161void HAL_SetAnalogTriggerLimitsVoltage(
162 HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
163 int32_t* status) {
164 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
165 if (trigger == nullptr) {
166 *status = HAL_HANDLE_ERROR;
167 return;
168 }
169
170 if (getHandleType(trigger->handle) != HAL_HandleEnum::AnalogInput) {
171 *status = HAL_HANDLE_ERROR;
172 return;
173 }
174 if (lower > upper) {
175 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
176 return;
177 }
178
179 // TODO: This depends on the averaged setting. Only raw values will work as
180 // is.
181 trigger->trigger->writeLowerLimit(
182 HAL_GetAnalogVoltsToValue(trigger->handle, lower, status), status);
183 trigger->trigger->writeUpperLimit(
184 HAL_GetAnalogVoltsToValue(trigger->handle, upper, status), status);
185}
186
187void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
188 HAL_Bool useAveragedValue, int32_t* status) {
189 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
190 if (trigger == nullptr) {
191 *status = HAL_HANDLE_ERROR;
192 return;
193 }
194 if (trigger->trigger->readSourceSelect_Filter(status) != 0 ||
195 trigger->trigger->readSourceSelect_DutyCycle(status) != 0) {
196 *status = INCOMPATIBLE_STATE;
197 // TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not
198 // support average and filtering at the same time.");
199 }
200 trigger->trigger->writeSourceSelect_Averaged(useAveragedValue, status);
201}
202
203void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
204 HAL_Bool useFilteredValue, int32_t* status) {
205 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
206 if (trigger == nullptr) {
207 *status = HAL_HANDLE_ERROR;
208 return;
209 }
210 if (trigger->trigger->readSourceSelect_Averaged(status) != 0 ||
211 trigger->trigger->readSourceSelect_DutyCycle(status) != 0) {
212 *status = INCOMPATIBLE_STATE;
213 // TODO: wpi_setWPIErrorWithContext(IncompatibleMode, "Hardware does not "
214 // "support average and filtering at the same time.");
215 }
216 trigger->trigger->writeSourceSelect_Filter(useFilteredValue, status);
217}
218
219HAL_Bool HAL_GetAnalogTriggerInWindow(
220 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
221 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
222 if (trigger == nullptr) {
223 *status = HAL_HANDLE_ERROR;
224 return false;
225 }
226 return trigger->trigger->readOutput_InHysteresis(trigger->index, status) != 0;
227}
228
229HAL_Bool HAL_GetAnalogTriggerTriggerState(
230 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
231 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
232 if (trigger == nullptr) {
233 *status = HAL_HANDLE_ERROR;
234 return false;
235 }
236 return trigger->trigger->readOutput_OverLimit(trigger->index, status) != 0;
237}
238
239HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
240 HAL_AnalogTriggerType type,
241 int32_t* status) {
242 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
243 if (trigger == nullptr) {
244 *status = HAL_HANDLE_ERROR;
245 return false;
246 }
247 bool result = false;
248 switch (type) {
249 case HAL_Trigger_kInWindow:
250 result =
251 trigger->trigger->readOutput_InHysteresis(trigger->index, status);
252 break;
253 case HAL_Trigger_kState:
254 result = trigger->trigger->readOutput_OverLimit(trigger->index, status);
255 break;
256 case HAL_Trigger_kRisingPulse:
257 case HAL_Trigger_kFallingPulse:
258 *status = ANALOG_TRIGGER_PULSE_OUTPUT_ERROR;
259 return false;
260 break;
261 }
262 return result;
263}
264
265int32_t HAL_GetAnalogTriggerFPGAIndex(
266 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
267 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
268 if (trigger == nullptr) {
269 *status = HAL_HANDLE_ERROR;
270 return -1;
271 }
272 return trigger->index;
273}
274
275} // extern "C"