blob: b611b35e8aed96f90a3cbff285dd13fcaaf77279 [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
James Kuszmaulcf324122023-01-14 14:07:17 -0800154void HAL_SetDigitalPWMPPS(HAL_DigitalPWMHandle pwmGenerator, double dutyCycle,
155 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 if (dutyCycle > 1.0) {
163 dutyCycle = 1.0;
164 }
165 if (dutyCycle < 0.0) {
166 dutyCycle = 0.0;
167 }
168 SimDigitalPWMData[id].dutyCycle = dutyCycle;
169}
170
Brian Silverman8fce7482020-01-05 13:18:21 -0800171void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
172 int32_t channel, int32_t* status) {
173 auto port = digitalPWMHandles->Get(pwmGenerator);
174 if (port == nullptr) {
175 *status = HAL_HANDLE_ERROR;
176 return;
177 }
178 int32_t id = *port;
179 SimDigitalPWMData[id].pin = channel;
180}
181
182void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
183 int32_t* status) {
184 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
185 if (port == nullptr) {
186 *status = HAL_HANDLE_ERROR;
187 return;
188 }
189 if (value != 0 && value != 1) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700190 if (value != 0) {
191 value = 1;
192 }
193 }
194 if (SimDIOData[port->channel].isInput) {
195 *status = PARAMETER_OUT_OF_RANGE;
196 hal::SetLastError(status, "Cannot set output of an input channel");
197 return;
Brian Silverman8fce7482020-01-05 13:18:21 -0800198 }
199 SimDIOData[port->channel].value = value;
200}
201
202void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
203 int32_t* status) {
204 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
205 if (port == nullptr) {
206 *status = HAL_HANDLE_ERROR;
207 return;
208 }
209
210 SimDIOData[port->channel].isInput = input;
211}
212
213HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
214 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
215 if (port == nullptr) {
216 *status = HAL_HANDLE_ERROR;
217 return false;
218 }
219 HAL_Bool value = SimDIOData[port->channel].value;
Austin Schuh812d0d12021-11-04 20:16:48 -0700220 if (value > 1) {
221 value = 1;
222 }
223 if (value < 0) {
224 value = 0;
225 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800226 return value;
227}
228
229HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
230 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
231 if (port == nullptr) {
232 *status = HAL_HANDLE_ERROR;
233 return false;
234 }
235 HAL_Bool value = SimDIOData[port->channel].isInput;
Austin Schuh812d0d12021-11-04 20:16:48 -0700236 if (value > 1) {
237 value = 1;
238 }
239 if (value < 0) {
240 value = 0;
241 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800242 return value;
243}
244
James Kuszmaulcf324122023-01-14 14:07:17 -0800245void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLengthSeconds,
Brian Silverman8fce7482020-01-05 13:18:21 -0800246 int32_t* status) {
247 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
248 if (port == nullptr) {
249 *status = HAL_HANDLE_ERROR;
250 return;
251 }
252 // TODO (Thad) Add this
253}
254
James Kuszmaulcf324122023-01-14 14:07:17 -0800255void HAL_PulseMultiple(uint32_t channelMask, double pulseLengthSeconds,
256 int32_t* status) {
257 // TODO (Thad) Add this
258}
259
Brian Silverman8fce7482020-01-05 13:18:21 -0800260HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
261 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
262 if (port == nullptr) {
263 *status = HAL_HANDLE_ERROR;
264 return false;
265 }
266 return false;
267 // TODO (Thad) Add this
268}
269
270HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
271 return false; // TODO(Thad) Figure this out
272}
273
274void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
275 int32_t* status) {
276 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
277 if (port == nullptr) {
278 *status = HAL_HANDLE_ERROR;
279 return;
280 }
281
282 // TODO(Thad) Figure this out
283}
284
285int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
286 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
287 if (port == nullptr) {
288 *status = HAL_HANDLE_ERROR;
289 return 0;
290 }
291 return 0;
292 // TODO(Thad) Figure this out
293}
294
295void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
296 // TODO(Thad) figure this out
297}
298
299int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
300 return 0; // TODO(Thad) figure this out
301}
302} // extern "C"