blob: 53b165c60d301d92c394e2f7602b35e4a41f34f1 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2017-2018 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* index, 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 *index = trigger->index;
87
88 SimAnalogTriggerData[trigger->index].initialized = true;
89
90 trigger->trigState = false;
91
92 return handle;
93}
94
95void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
96 int32_t* status) {
97 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
98 analogTriggerHandles->Free(analogTriggerHandle);
99 if (trigger == nullptr) return;
100 SimAnalogTriggerData[trigger->index].initialized = false;
101 // caller owns the analog input handle.
102}
103
104static double GetAnalogValueToVoltage(
105 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t value,
106 int32_t* status) {
107 int32_t LSBWeight = HAL_GetAnalogLSBWeight(analogTriggerHandle, status);
108 int32_t offset = HAL_GetAnalogOffset(analogTriggerHandle, status);
109
110 double voltage = LSBWeight * 1.0e-9 * value - offset * 1.0e-9;
111 return voltage;
112}
113
114void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
115 int32_t lower, int32_t upper,
116 int32_t* status) {
117 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
118 if (trigger == nullptr) {
119 *status = HAL_HANDLE_ERROR;
120 return;
121 }
122 if (lower > upper) {
123 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
124 }
125
126 double trigLower =
127 GetAnalogValueToVoltage(trigger->analogHandle, lower, status);
128 if (status != 0) return;
129 double trigUpper =
130 GetAnalogValueToVoltage(trigger->analogHandle, upper, status);
131 if (status != 0) return;
132
133 SimAnalogTriggerData[trigger->index].triggerUpperBound = trigUpper;
134 SimAnalogTriggerData[trigger->index].triggerLowerBound = trigLower;
135}
136void HAL_SetAnalogTriggerLimitsVoltage(
137 HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
138 int32_t* status) {
139 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
140 if (trigger == nullptr) {
141 *status = HAL_HANDLE_ERROR;
142 return;
143 }
144 if (lower > upper) {
145 *status = ANALOG_TRIGGER_LIMIT_ORDER_ERROR;
146 }
147
148 SimAnalogTriggerData[trigger->index].triggerUpperBound = upper;
149 SimAnalogTriggerData[trigger->index].triggerLowerBound = lower;
150}
151void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
152 HAL_Bool useAveragedValue, int32_t* status) {
153 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
154 if (trigger == nullptr) {
155 *status = HAL_HANDLE_ERROR;
156 return;
157 }
158
159 AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
160
161 if (triggerData->triggerMode.Get() == HALSIM_AnalogTriggerFiltered) {
162 *status = INCOMPATIBLE_STATE;
163 return;
164 }
165
166 auto setVal = useAveragedValue ? HALSIM_AnalogTriggerAveraged
167 : HALSIM_AnalogTriggerUnassigned;
168 triggerData->triggerMode = setVal;
169}
170void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
171 HAL_Bool useFilteredValue, int32_t* status) {
172 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
173 if (trigger == nullptr) {
174 *status = HAL_HANDLE_ERROR;
175 return;
176 }
177
178 AnalogTriggerData* triggerData = &SimAnalogTriggerData[trigger->index];
179
180 if (triggerData->triggerMode.Get() == HALSIM_AnalogTriggerAveraged) {
181 *status = INCOMPATIBLE_STATE;
182 return;
183 }
184
185 auto setVal = useFilteredValue ? HALSIM_AnalogTriggerAveraged
186 : HALSIM_AnalogTriggerUnassigned;
187 triggerData->triggerMode = setVal;
188}
189
190static double GetTriggerValue(AnalogTrigger* trigger, int32_t* status) {
191 auto analogIn = analogInputHandles->Get(trigger->analogHandle);
192 if (analogIn == nullptr) {
193 // Returning HAL Handle Error, but going to ignore lower down
194 *status = HAL_HANDLE_ERROR;
195 return 0.0;
196 }
197
198 return SimAnalogInData[analogIn->channel].voltage;
199}
200
201HAL_Bool HAL_GetAnalogTriggerInWindow(
202 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
203 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
204 if (trigger == nullptr) {
205 *status = HAL_HANDLE_ERROR;
206 return false;
207 }
208
209 double voltage = GetTriggerValue(trigger.get(), status);
210 if (*status == HAL_HANDLE_ERROR) {
211 // Don't error if analog has been destroyed
212 *status = 0;
213 return false;
214 }
215
216 double trigUpper = SimAnalogTriggerData[trigger->index].triggerUpperBound;
217 double trigLower = SimAnalogTriggerData[trigger->index].triggerLowerBound;
218
219 return voltage >= trigLower && voltage <= trigUpper;
220}
221HAL_Bool HAL_GetAnalogTriggerTriggerState(
222 HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status) {
223 auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
224 if (trigger == nullptr) {
225 *status = HAL_HANDLE_ERROR;
226 return false;
227 }
228
229 double voltage = GetTriggerValue(trigger.get(), status);
230 if (*status == HAL_HANDLE_ERROR) {
231 // Don't error if analog has been destroyed
232 *status = 0;
233 return false;
234 }
235
236 double trigUpper = SimAnalogTriggerData[trigger->index].triggerUpperBound;
237 double trigLower = SimAnalogTriggerData[trigger->index].triggerLowerBound;
238
239 if (voltage < trigLower) {
240 trigger->trigState = false;
241 return false;
242 }
243 if (voltage > trigUpper) {
244 trigger->trigState = true;
245 return true;
246 }
247 return trigger->trigState;
248}
249HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
250 HAL_AnalogTriggerType type,
251 int32_t* status) {
252 if (type == HAL_Trigger_kInWindow) {
253 return HAL_GetAnalogTriggerInWindow(analogTriggerHandle, status);
254 } else if (type == HAL_Trigger_kState) {
255 return HAL_GetAnalogTriggerTriggerState(analogTriggerHandle, status);
256 } else {
257 *status = ANALOG_TRIGGER_PULSE_OUTPUT_ERROR;
258 return false;
259 }
260}
261} // extern "C"