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