blob: 62bfebc99ef9f5422be133f23b535af218861ad9 [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
Austin Schuh1e69f942020-11-14 15:06:14 -08002/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
Brian Silverman8fce7482020-01-05 13:18:21 -08003/* 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;
Austin Schuh1e69f942020-11-14 15:06:14 -080088 SimAnalogTriggerData[trigger->index].inputPort = analog_port->channel;
Brian Silverman8fce7482020-01-05 13:18:21 -080089
90 trigger->trigState = false;
91
92 return handle;
93}
94
95HAL_AnalogTriggerHandle HAL_InitializeAnalogTriggerDutyCycle(
96 HAL_DutyCycleHandle dutyCycleHandle, int32_t* status) {
97 *status = HAL_SIM_NOT_SUPPORTED;
98 return HAL_kInvalidHandle;
99}
100
101void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
102 int32_t* status) {
103 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
104 analogTriggerHandles->Free(analogTriggerHandle);
105 if (trigger == nullptr) return;
106 SimAnalogTriggerData[trigger->index].initialized = false;
107 // caller owns the analog input handle.
108}
109
110static double GetAnalogValueToVoltage(
111 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t value,
112 int32_t* status) {
113 int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogTriggerHandle, status);
114 int32_t offset = HAL_GetAnalogOffset(analogTriggerHandle, status);
115
116 double voltage = LSBWeight * 1.0e-9 * value - offset * 1.0e-9;
117 return voltage;
118}
119
120void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
121 int32_t lower, int32_t upper,
122 int32_t* status) {
123 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
124 if (trigger == nullptr) {
125 *status = HAL_HANDLE_ERROR;
126 return;
127 }
128 if (lower > upper) {
129 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
130 }
131
132 double trigLower =
133 GetAnalogValueToVoltage(trigger->analogHandle, lower, status);
134 if (status != 0) return;
135 double trigUpper =
136 GetAnalogValueToVoltage(trigger->analogHandle, upper, status);
137 if (status != 0) return;
138
139 SimAnalogTriggerData[trigger->index].triggerUpperBound = trigUpper;
140 SimAnalogTriggerData[trigger->index].triggerLowerBound = trigLower;
141}
142
143void HAL_SetAnalogTriggerLimitsDutyCycle(
144 HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
145 int32_t* status) {
146 *status = HAL_SIM_NOT_SUPPORTED;
147}
148
149void HAL_SetAnalogTriggerLimitsVoltage(
150 HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
151 int32_t* status) {
152 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
153 if (trigger == nullptr) {
154 *status = HAL_HANDLE_ERROR;
155 return;
156 }
157 if (lower > upper) {
158 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
159 }
160
161 SimAnalogTriggerData[trigger->index].triggerUpperBound = upper;
162 SimAnalogTriggerData[trigger->index].triggerLowerBound = lower;
163}
164void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
165 HAL_Bool useAveragedValue, int32_t* status) {
166 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
167 if (trigger == nullptr) {
168 *status = HAL_HANDLE_ERROR;
169 return;
170 }
171
172 AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
173
174 if (triggerData->triggerMode.Get() != HALSIM_AnalogTriggerUnassigned) {
175 *status = INCOMPATIBLE_STATE;
176 return;
177 }
178
179 auto setVal = useAveragedValue ? HALSIM_AnalogTriggerAveraged
180 : HALSIM_AnalogTriggerUnassigned;
181 triggerData->triggerMode = setVal;
182}
183
184void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
185 HAL_Bool useFilteredValue, int32_t* status) {
186 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
187 if (trigger == nullptr) {
188 *status = HAL_HANDLE_ERROR;
189 return;
190 }
191
192 AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
193
194 if (triggerData->triggerMode.Get() != HALSIM_AnalogTriggerUnassigned) {
195 *status = INCOMPATIBLE_STATE;
196 return;
197 }
198
199 auto setVal = useFilteredValue ? HALSIM_AnalogTriggerFiltered
200 : HALSIM_AnalogTriggerUnassigned;
201 triggerData->triggerMode = setVal;
202}
203
204static double GetTriggerValue(AnalogTrigger* trigger, int32_t* status) {
205 auto analogIn = analogInputHandles->Get(trigger->analogHandle);
206 if (analogIn == nullptr) {
207 // Returning HAL Handle Error, but going to ignore lower down
208 *status = HAL_HANDLE_ERROR;
209 return 0.0;
210 }
211
212 return SimAnalogInData[analogIn->channel].voltage;
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
223 double voltage = GetTriggerValue(trigger.get(), status);
224 if (*status == HAL_HANDLE_ERROR) {
225 // Don't error if analog has been destroyed
226 *status = 0;
227 return false;
228 }
229
230 double trigUpper = SimAnalogTriggerData[trigger->index].triggerUpperBound;
231 double trigLower = SimAnalogTriggerData[trigger->index].triggerLowerBound;
232
233 return voltage >= trigLower && voltage <= trigUpper;
234}
235HAL_Bool HAL_GetAnalogTriggerTriggerState(
236 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
237 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
238 if (trigger == nullptr) {
239 *status = HAL_HANDLE_ERROR;
240 return false;
241 }
242
243 double voltage = GetTriggerValue(trigger.get(), status);
244 if (*status == HAL_HANDLE_ERROR) {
245 // Don't error if analog has been destroyed
246 *status = 0;
247 return false;
248 }
249
250 double trigUpper = SimAnalogTriggerData[trigger->index].triggerUpperBound;
251 double trigLower = SimAnalogTriggerData[trigger->index].triggerLowerBound;
252
253 if (voltage < trigLower) {
254 trigger->trigState = false;
255 return false;
256 }
257 if (voltage > trigUpper) {
258 trigger->trigState = true;
259 return true;
260 }
261 return trigger->trigState;
262}
263HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
264 HAL_AnalogTriggerType type,
265 int32_t* status) {
266 if (type == HAL_Trigger_kInWindow) {
267 return HAL_GetAnalogTriggerInWindow(analogTriggerHandle, status);
268 } else if (type == HAL_Trigger_kState) {
269 return HAL_GetAnalogTriggerTriggerState(analogTriggerHandle, status);
270 } else {
271 *status = ANALOG_TRIGGER_PULSE_OUTPUT_ERROR;
272 return false;
273 }
274}
275
276int32_t HAL_GetAnalogTriggerFPGAIndex(
277 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
278 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
279 if (trigger == nullptr) {
280 *status = HAL_HANDLE_ERROR;
281 return -1;
282 }
283 return trigger->index;
284}
285
286} // extern "C"