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