blob: 1b744a1625d86a84aba8d5dd4fabe8443fff010d [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/DIO.h"
6
Brian Silverman8fce7482020-01-05 13:18:21 -08007#include "DigitalInternal.h"
8#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -07009#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080010#include "PortsInternal.h"
11#include "hal/handles/HandlesInternal.h"
12#include "hal/handles/LimitedHandleResource.h"
13#include "mockdata/DIODataInternal.h"
14#include "mockdata/DigitalPWMDataInternal.h"
15
16using namespace hal;
17
18static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
19 kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>*
20 digitalPWMHandles;
21
Austin Schuh812d0d12021-11-04 20:16:48 -070022namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080023void InitializeDIO() {
24 static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
25 kNumDigitalPWMOutputs,
26 HAL_HandleEnum::DigitalPWM>
27 dpH;
28 digitalPWMHandles = &dpH;
29}
Austin Schuh812d0d12021-11-04 20:16:48 -070030} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080031
32extern "C" {
33
34HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
Austin Schuh812d0d12021-11-04 20:16:48 -070035 HAL_Bool input,
36 const char* allocationLocation,
37 int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -080038 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -080039
40 int16_t channel = getPortHandleChannel(portHandle);
41 if (channel == InvalidHandleIndex) {
Austin Schuh812d0d12021-11-04 20:16:48 -070042 *status = RESOURCE_OUT_OF_RANGE;
43 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
44 kNumDigitalChannels, channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080045 return HAL_kInvalidHandle;
46 }
47
Austin Schuh812d0d12021-11-04 20:16:48 -070048 HAL_DigitalHandle handle;
Brian Silverman8fce7482020-01-05 13:18:21 -080049
Austin Schuh812d0d12021-11-04 20:16:48 -070050 auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO,
51 &handle, status);
52
53 if (*status != 0) {
54 if (port) {
55 hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
56 port->previousAllocation);
57 } else {
58 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
59 kNumDigitalChannels, channel);
60 }
Brian Silverman8fce7482020-01-05 13:18:21 -080061 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
Brian Silverman8fce7482020-01-05 13:18:21 -080062 }
63
64 port->channel = static_cast<uint8_t>(channel);
65
66 SimDIOData[channel].initialized = true;
67 SimDIOData[channel].isInput = input;
68 SimDIOData[channel].simDevice = 0;
Austin Schuh812d0d12021-11-04 20:16:48 -070069 port->previousAllocation = allocationLocation ? allocationLocation : "";
Brian Silverman8fce7482020-01-05 13:18:21 -080070
71 return handle;
72}
73
74HAL_Bool HAL_CheckDIOChannel(int32_t channel) {
75 return channel < kNumDigitalChannels && channel >= 0;
76}
77
78void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
79 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
80 // no status, so no need to check for a proper free.
81 digitalChannelHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
Austin Schuh812d0d12021-11-04 20:16:48 -070082 if (port == nullptr) {
83 return;
84 }
Brian Silverman8fce7482020-01-05 13:18:21 -080085 SimDIOData[port->channel].initialized = false;
86}
87
88void HAL_SetDIOSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
89 auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
Austin Schuh812d0d12021-11-04 20:16:48 -070090 if (port == nullptr) {
91 return;
92 }
Brian Silverman8fce7482020-01-05 13:18:21 -080093 SimDIOData[port->channel].simDevice = device;
94}
95
96HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
97 auto handle = digitalPWMHandles->Allocate();
98 if (handle == HAL_kInvalidHandle) {
99 *status = NO_AVAILABLE_RESOURCES;
100 return HAL_kInvalidHandle;
101 }
102
103 auto id = digitalPWMHandles->Get(handle);
104 if (id == nullptr) { // would only occur on thread issue.
105 *status = HAL_HANDLE_ERROR;
106 return HAL_kInvalidHandle;
107 }
108 *id = static_cast<uint8_t>(getHandleIndex(handle));
109
110 SimDigitalPWMData[*id].initialized = true;
111
112 return handle;
113}
114
115void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status) {
116 auto port = digitalPWMHandles->Get(pwmGenerator);
117 digitalPWMHandles->Free(pwmGenerator);
Austin Schuh812d0d12021-11-04 20:16:48 -0700118 if (port == nullptr) {
119 return;
120 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800121 int32_t id = *port;
122 SimDigitalPWMData[id].initialized = false;
123}
124
125void HAL_SetDigitalPWMRate(double rate, int32_t* status) {
126 // Currently rounding in the log rate domain... heavy weight toward picking a
127 // higher freq.
128 // TODO: Round in the linear rate domain.
129 // uint8_t pwmPeriodPower = static_cast<uint8_t>(
130 // std::log(1.0 / (kExpectedLoopTiming * 0.25E-6 * rate)) /
131 // std::log(2.0) +
132 // 0.5);
133 // TODO(THAD) : Add a case to set this in the simulator
134 // digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
135}
136
137void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
138 double dutyCycle, int32_t* status) {
139 auto port = digitalPWMHandles->Get(pwmGenerator);
140 if (port == nullptr) {
141 *status = HAL_HANDLE_ERROR;
142 return;
143 }
144 int32_t id = *port;
Austin Schuh812d0d12021-11-04 20:16:48 -0700145 if (dutyCycle > 1.0) {
146 dutyCycle = 1.0;
147 }
148 if (dutyCycle < 0.0) {
149 dutyCycle = 0.0;
150 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800151 SimDigitalPWMData[id].dutyCycle = dutyCycle;
152}
153
154void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
155 int32_t channel, int32_t* status) {
156 auto port = digitalPWMHandles->Get(pwmGenerator);
157 if (port == nullptr) {
158 *status = HAL_HANDLE_ERROR;
159 return;
160 }
161 int32_t id = *port;
162 SimDigitalPWMData[id].pin = channel;
163}
164
165void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
166 int32_t* status) {
167 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
168 if (port == nullptr) {
169 *status = HAL_HANDLE_ERROR;
170 return;
171 }
172 if (value != 0 && value != 1) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700173 if (value != 0) {
174 value = 1;
175 }
176 }
177 if (SimDIOData[port->channel].isInput) {
178 *status = PARAMETER_OUT_OF_RANGE;
179 hal::SetLastError(status, "Cannot set output of an input channel");
180 return;
Brian Silverman8fce7482020-01-05 13:18:21 -0800181 }
182 SimDIOData[port->channel].value = value;
183}
184
185void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
186 int32_t* status) {
187 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
188 if (port == nullptr) {
189 *status = HAL_HANDLE_ERROR;
190 return;
191 }
192
193 SimDIOData[port->channel].isInput = input;
194}
195
196HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
197 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
198 if (port == nullptr) {
199 *status = HAL_HANDLE_ERROR;
200 return false;
201 }
202 HAL_Bool value = SimDIOData[port->channel].value;
Austin Schuh812d0d12021-11-04 20:16:48 -0700203 if (value > 1) {
204 value = 1;
205 }
206 if (value < 0) {
207 value = 0;
208 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800209 return value;
210}
211
212HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
213 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
214 if (port == nullptr) {
215 *status = HAL_HANDLE_ERROR;
216 return false;
217 }
218 HAL_Bool value = SimDIOData[port->channel].isInput;
Austin Schuh812d0d12021-11-04 20:16:48 -0700219 if (value > 1) {
220 value = 1;
221 }
222 if (value < 0) {
223 value = 0;
224 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800225 return value;
226}
227
228void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength,
229 int32_t* status) {
230 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
231 if (port == nullptr) {
232 *status = HAL_HANDLE_ERROR;
233 return;
234 }
235 // TODO (Thad) Add this
236}
237
238HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
239 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
240 if (port == nullptr) {
241 *status = HAL_HANDLE_ERROR;
242 return false;
243 }
244 return false;
245 // TODO (Thad) Add this
246}
247
248HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
249 return false; // TODO(Thad) Figure this out
250}
251
252void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
253 int32_t* status) {
254 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
255 if (port == nullptr) {
256 *status = HAL_HANDLE_ERROR;
257 return;
258 }
259
260 // TODO(Thad) Figure this out
261}
262
263int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
264 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
265 if (port == nullptr) {
266 *status = HAL_HANDLE_ERROR;
267 return 0;
268 }
269 return 0;
270 // TODO(Thad) Figure this out
271}
272
273void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
274 // TODO(Thad) figure this out
275}
276
277int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
278 return 0; // TODO(Thad) figure this out
279}
280} // extern "C"