blob: 50c4ab49282105cefad22b30da59648d62da0311 [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 "HALInitializer.h"
9#include "PortsInternal.h"
10#include "hal/AnalogInput.h"
11#include "hal/Errors.h"
12#include "hal/handles/HandlesInternal.h"
13#include "hal/handles/LimitedHandleResource.h"
14#include "mockdata/AnalogInDataInternal.h"
15#include "mockdata/AnalogTriggerDataInternal.h"
16
17namespace {
18struct AnalogTrigger {
19 HAL_AnalogInputHandle analogHandle;
20 uint8_t index;
21 HAL_Bool trigState;
22};
23} // namespace
24
25using namespace hal;
26
27static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
28 kNumAnalogTriggers, HAL_HandleEnum::AnalogTrigger>*
29 analogTriggerHandles;
30
Austin Schuh812d0d12021-11-04 20:16:48 -070031namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080032void InitializeAnalogTrigger() {
33 static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
34 kNumAnalogTriggers,
35 HAL_HandleEnum::AnalogTrigger>
36 atH;
37 analogTriggerHandles = &atH;
38}
Austin Schuh812d0d12021-11-04 20:16:48 -070039} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080040
41int32_t hal::GetAnalogTriggerInputIndex(HAL_AnalogTriggerHandle handle,
42 int32_t* status) {
43 auto trigger = analogTriggerHandles->Get(handle);
44 if (trigger == nullptr) {
45 *status = HAL_HANDLE_ERROR;
46 return -1;
47 }
48
49 auto analog_port = analogInputHandles->Get(trigger->analogHandle);
50 if (analog_port == nullptr) {
51 *status = HAL_HANDLE_ERROR;
52 return -1;
53 }
54
55 return analog_port->channel;
56}
57
58extern "C" {
59
60HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
61 HAL_AnalogInputHandle portHandle, int32_t* status) {
62 hal::init::CheckInit();
63 // ensure we are given a valid and active AnalogInput handle
64 auto analog_port = analogInputHandles->Get(portHandle);
65 if (analog_port == nullptr) {
66 *status = HAL_HANDLE_ERROR;
67 return HAL_kInvalidHandle;
68 }
69 HAL_AnalogTriggerHandle handle = analogTriggerHandles->Allocate();
70 if (handle == HAL_kInvalidHandle) {
71 *status = NO_AVAILABLE_RESOURCES;
72 return HAL_kInvalidHandle;
73 }
74 auto trigger = analogTriggerHandles->Get(handle);
75 if (trigger == nullptr) { // would only occur on thread issue
76 *status = HAL_HANDLE_ERROR;
77 return HAL_kInvalidHandle;
78 }
79 trigger->analogHandle = portHandle;
80 trigger->index = static_cast<uint8_t>(getHandleIndex(handle));
81
82 SimAnalogTriggerData[trigger->index].initialized = true;
Austin Schuh1e69f942020-11-14 15:06:14 -080083 SimAnalogTriggerData[trigger->index].inputPort = analog_port->channel;
Brian Silverman8fce7482020-01-05 13:18:21 -080084
85 trigger->trigState = false;
86
87 return handle;
88}
89
90HAL_AnalogTriggerHandle HAL_InitializeAnalogTriggerDutyCycle(
91 HAL_DutyCycleHandle dutyCycleHandle, int32_t* status) {
92 *status = HAL_SIM_NOT_SUPPORTED;
93 return HAL_kInvalidHandle;
94}
95
96void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
97 int32_t* status) {
98 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
99 analogTriggerHandles->Free(analogTriggerHandle);
Austin Schuh812d0d12021-11-04 20:16:48 -0700100 if (trigger == nullptr) {
101 return;
102 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800103 SimAnalogTriggerData[trigger->index].initialized = false;
104 // caller owns the analog input handle.
105}
106
107static double GetAnalogValueToVoltage(
108 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t value,
109 int32_t* status) {
110 int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogTriggerHandle, status);
111 int32_t offset = HAL_GetAnalogOffset(analogTriggerHandle, status);
112
113 double voltage = LSBWeight * 1.0e-9 * value - offset * 1.0e-9;
114 return voltage;
115}
116
117void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
118 int32_t lower, int32_t upper,
119 int32_t* status) {
120 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
121 if (trigger == nullptr) {
122 *status = HAL_HANDLE_ERROR;
123 return;
124 }
125 if (lower > upper) {
126 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
127 }
128
129 double trigLower =
130 GetAnalogValueToVoltage(trigger->analogHandle, lower, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700131 if (status != nullptr) {
132 return;
133 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800134 double trigUpper =
135 GetAnalogValueToVoltage(trigger->analogHandle, upper, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700136 if (status != nullptr) {
137 return;
138 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800139
140 SimAnalogTriggerData[trigger->index].triggerUpperBound = trigUpper;
141 SimAnalogTriggerData[trigger->index].triggerLowerBound = trigLower;
142}
143
144void HAL_SetAnalogTriggerLimitsDutyCycle(
145 HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
146 int32_t* status) {
147 *status = HAL_SIM_NOT_SUPPORTED;
148}
149
150void HAL_SetAnalogTriggerLimitsVoltage(
151 HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
152 int32_t* status) {
153 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
154 if (trigger == nullptr) {
155 *status = HAL_HANDLE_ERROR;
156 return;
157 }
158 if (lower > upper) {
159 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
160 }
161
162 SimAnalogTriggerData[trigger->index].triggerUpperBound = upper;
163 SimAnalogTriggerData[trigger->index].triggerLowerBound = lower;
164}
165void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
166 HAL_Bool useAveragedValue, int32_t* status) {
167 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
168 if (trigger == nullptr) {
169 *status = HAL_HANDLE_ERROR;
170 return;
171 }
172
173 AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
174
175 if (triggerData->triggerMode.Get() != HALSIM_AnalogTriggerUnassigned) {
176 *status = INCOMPATIBLE_STATE;
177 return;
178 }
179
180 auto setVal = useAveragedValue ? HALSIM_AnalogTriggerAveraged
181 : HALSIM_AnalogTriggerUnassigned;
182 triggerData->triggerMode = setVal;
183}
184
185void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
186 HAL_Bool useFilteredValue, int32_t* status) {
187 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
188 if (trigger == nullptr) {
189 *status = HAL_HANDLE_ERROR;
190 return;
191 }
192
193 AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
194
195 if (triggerData->triggerMode.Get() != HALSIM_AnalogTriggerUnassigned) {
196 *status = INCOMPATIBLE_STATE;
197 return;
198 }
199
200 auto setVal = useFilteredValue ? HALSIM_AnalogTriggerFiltered
201 : HALSIM_AnalogTriggerUnassigned;
202 triggerData->triggerMode = setVal;
203}
204
205static double GetTriggerValue(AnalogTrigger* trigger, int32_t* status) {
206 auto analogIn = analogInputHandles->Get(trigger->analogHandle);
207 if (analogIn == nullptr) {
208 // Returning HAL Handle Error, but going to ignore lower down
209 *status = HAL_HANDLE_ERROR;
210 return 0.0;
211 }
212
213 return SimAnalogInData[analogIn->channel].voltage;
214}
215
216HAL_Bool HAL_GetAnalogTriggerInWindow(
217 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
218 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
219 if (trigger == nullptr) {
220 *status = HAL_HANDLE_ERROR;
221 return false;
222 }
223
224 double voltage = GetTriggerValue(trigger.get(), status);
225 if (*status == HAL_HANDLE_ERROR) {
226 // Don't error if analog has been destroyed
227 *status = 0;
228 return false;
229 }
230
231 double trigUpper = SimAnalogTriggerData[trigger->index].triggerUpperBound;
232 double trigLower = SimAnalogTriggerData[trigger->index].triggerLowerBound;
233
234 return voltage >= trigLower && voltage <= trigUpper;
235}
236HAL_Bool HAL_GetAnalogTriggerTriggerState(
237 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
238 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
239 if (trigger == nullptr) {
240 *status = HAL_HANDLE_ERROR;
241 return false;
242 }
243
244 double voltage = GetTriggerValue(trigger.get(), status);
245 if (*status == HAL_HANDLE_ERROR) {
246 // Don't error if analog has been destroyed
247 *status = 0;
248 return false;
249 }
250
251 double trigUpper = SimAnalogTriggerData[trigger->index].triggerUpperBound;
252 double trigLower = SimAnalogTriggerData[trigger->index].triggerLowerBound;
253
254 if (voltage < trigLower) {
255 trigger->trigState = false;
256 return false;
257 }
258 if (voltage > trigUpper) {
259 trigger->trigState = true;
260 return true;
261 }
262 return trigger->trigState;
263}
264HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
265 HAL_AnalogTriggerType type,
266 int32_t* status) {
267 if (type == HAL_Trigger_kInWindow) {
268 return HAL_GetAnalogTriggerInWindow(analogTriggerHandle, status);
269 } else if (type == HAL_Trigger_kState) {
270 return HAL_GetAnalogTriggerTriggerState(analogTriggerHandle, status);
271 } else {
272 *status = ANALOG_TRIGGER_PULSE_OUTPUT_ERROR;
273 return false;
274 }
275}
276
277int32_t HAL_GetAnalogTriggerFPGAIndex(
278 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
279 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
280 if (trigger == nullptr) {
281 *status = HAL_HANDLE_ERROR;
282 return -1;
283 }
284 return trigger->index;
285}
286
287} // extern "C"