blob: 21581361a0218babfd8f937fb3352a5afa4b7c31 [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2016-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/DIO.h"
9
10#include <cmath>
11
12#include "DigitalInternal.h"
13#include "HALInitializer.h"
14#include "PortsInternal.h"
15#include "hal/handles/HandlesInternal.h"
16#include "hal/handles/LimitedHandleResource.h"
17#include "mockdata/DIODataInternal.h"
18#include "mockdata/DigitalPWMDataInternal.h"
19
20using namespace hal;
21
22static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
23 kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>*
24 digitalPWMHandles;
25
26namespace hal {
27namespace init {
28void InitializeDIO() {
29 static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
30 kNumDigitalPWMOutputs,
31 HAL_HandleEnum::DigitalPWM>
32 dpH;
33 digitalPWMHandles = &dpH;
34}
35} // namespace init
36} // namespace hal
37
38extern "C" {
39
40HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
41 HAL_Bool input, int32_t* status) {
42 hal::init::CheckInit();
43 if (*status != 0) return HAL_kInvalidHandle;
44
45 int16_t channel = getPortHandleChannel(portHandle);
46 if (channel == InvalidHandleIndex) {
47 *status = PARAMETER_OUT_OF_RANGE;
48 return HAL_kInvalidHandle;
49 }
50
51 auto handle =
52 digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, status);
53
54 if (*status != 0)
55 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
56
57 auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
58 if (port == nullptr) { // would only occur on thread issue.
59 *status = HAL_HANDLE_ERROR;
60 return HAL_kInvalidHandle;
61 }
62
63 port->channel = static_cast<uint8_t>(channel);
64
65 SimDIOData[channel].initialized = true;
66 SimDIOData[channel].isInput = input;
67 SimDIOData[channel].simDevice = 0;
68
69 return handle;
70}
71
72HAL_Bool HAL_CheckDIOChannel(int32_t channel) {
73 return channel < kNumDigitalChannels && channel >= 0;
74}
75
76void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
77 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
78 // no status, so no need to check for a proper free.
79 digitalChannelHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
80 if (port == nullptr) return;
81 SimDIOData[port->channel].initialized = false;
82}
83
84void HAL_SetDIOSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
85 auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
86 if (port == nullptr) return;
87 SimDIOData[port->channel].simDevice = device;
88}
89
90HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
91 auto handle = digitalPWMHandles->Allocate();
92 if (handle == HAL_kInvalidHandle) {
93 *status = NO_AVAILABLE_RESOURCES;
94 return HAL_kInvalidHandle;
95 }
96
97 auto id = digitalPWMHandles->Get(handle);
98 if (id == nullptr) { // would only occur on thread issue.
99 *status = HAL_HANDLE_ERROR;
100 return HAL_kInvalidHandle;
101 }
102 *id = static_cast<uint8_t>(getHandleIndex(handle));
103
104 SimDigitalPWMData[*id].initialized = true;
105
106 return handle;
107}
108
109void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status) {
110 auto port = digitalPWMHandles->Get(pwmGenerator);
111 digitalPWMHandles->Free(pwmGenerator);
112 if (port == nullptr) return;
113 int32_t id = *port;
114 SimDigitalPWMData[id].initialized = false;
115}
116
117void HAL_SetDigitalPWMRate(double rate, int32_t* status) {
118 // Currently rounding in the log rate domain... heavy weight toward picking a
119 // higher freq.
120 // TODO: Round in the linear rate domain.
121 // uint8_t pwmPeriodPower = static_cast<uint8_t>(
122 // std::log(1.0 / (kExpectedLoopTiming * 0.25E-6 * rate)) /
123 // std::log(2.0) +
124 // 0.5);
125 // TODO(THAD) : Add a case to set this in the simulator
126 // digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
127}
128
129void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
130 double dutyCycle, int32_t* status) {
131 auto port = digitalPWMHandles->Get(pwmGenerator);
132 if (port == nullptr) {
133 *status = HAL_HANDLE_ERROR;
134 return;
135 }
136 int32_t id = *port;
137 if (dutyCycle > 1.0) dutyCycle = 1.0;
138 if (dutyCycle < 0.0) dutyCycle = 0.0;
139 SimDigitalPWMData[id].dutyCycle = dutyCycle;
140}
141
142void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
143 int32_t channel, int32_t* status) {
144 auto port = digitalPWMHandles->Get(pwmGenerator);
145 if (port == nullptr) {
146 *status = HAL_HANDLE_ERROR;
147 return;
148 }
149 int32_t id = *port;
150 SimDigitalPWMData[id].pin = channel;
151}
152
153void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
154 int32_t* status) {
155 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
156 if (port == nullptr) {
157 *status = HAL_HANDLE_ERROR;
158 return;
159 }
160 if (value != 0 && value != 1) {
161 if (value != 0) value = 1;
162 }
163 SimDIOData[port->channel].value = value;
164}
165
166void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
167 int32_t* status) {
168 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
169 if (port == nullptr) {
170 *status = HAL_HANDLE_ERROR;
171 return;
172 }
173
174 SimDIOData[port->channel].isInput = input;
175}
176
177HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
178 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
179 if (port == nullptr) {
180 *status = HAL_HANDLE_ERROR;
181 return false;
182 }
183 HAL_Bool value = SimDIOData[port->channel].value;
184 if (value > 1) value = 1;
185 if (value < 0) value = 0;
186 return value;
187}
188
189HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
190 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
191 if (port == nullptr) {
192 *status = HAL_HANDLE_ERROR;
193 return false;
194 }
195 HAL_Bool value = SimDIOData[port->channel].isInput;
196 if (value > 1) value = 1;
197 if (value < 0) value = 0;
198 return value;
199}
200
201void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength,
202 int32_t* status) {
203 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
204 if (port == nullptr) {
205 *status = HAL_HANDLE_ERROR;
206 return;
207 }
208 // TODO (Thad) Add this
209}
210
211HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
212 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
213 if (port == nullptr) {
214 *status = HAL_HANDLE_ERROR;
215 return false;
216 }
217 return false;
218 // TODO (Thad) Add this
219}
220
221HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
222 return false; // TODO(Thad) Figure this out
223}
224
225void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
226 int32_t* status) {
227 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
228 if (port == nullptr) {
229 *status = HAL_HANDLE_ERROR;
230 return;
231 }
232
233 // TODO(Thad) Figure this out
234}
235
236int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
237 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
238 if (port == nullptr) {
239 *status = HAL_HANDLE_ERROR;
240 return 0;
241 }
242 return 0;
243 // TODO(Thad) Figure this out
244}
245
246void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
247 // TODO(Thad) figure this out
248}
249
250int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
251 return 0; // TODO(Thad) figure this out
252}
253} // extern "C"