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