blob: f827bbf956045a60b419d63c768271254e9cfc05 [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>(
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800130 // std::log2(1.0 / (kExpectedLoopTiming * 0.25E-6 * rate)) + 0.5);
Brian Silverman8fce7482020-01-05 13:18:21 -0800131 // TODO(THAD) : Add a case to set this in the simulator
132 // digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
133}
134
135void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
136 double dutyCycle, int32_t* status) {
137 auto port = digitalPWMHandles->Get(pwmGenerator);
138 if (port == nullptr) {
139 *status = HAL_HANDLE_ERROR;
140 return;
141 }
142 int32_t id = *port;
Austin Schuh812d0d12021-11-04 20:16:48 -0700143 if (dutyCycle > 1.0) {
144 dutyCycle = 1.0;
145 }
146 if (dutyCycle < 0.0) {
147 dutyCycle = 0.0;
148 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800149 SimDigitalPWMData[id].dutyCycle = dutyCycle;
150}
151
James Kuszmaulcf324122023-01-14 14:07:17 -0800152void HAL_SetDigitalPWMPPS(HAL_DigitalPWMHandle pwmGenerator, double dutyCycle,
153 int32_t* status) {
154 auto port = digitalPWMHandles->Get(pwmGenerator);
155 if (port == nullptr) {
156 *status = HAL_HANDLE_ERROR;
157 return;
158 }
159 int32_t id = *port;
160 if (dutyCycle > 1.0) {
161 dutyCycle = 1.0;
162 }
163 if (dutyCycle < 0.0) {
164 dutyCycle = 0.0;
165 }
166 SimDigitalPWMData[id].dutyCycle = dutyCycle;
167}
168
Brian Silverman8fce7482020-01-05 13:18:21 -0800169void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
170 int32_t channel, int32_t* status) {
171 auto port = digitalPWMHandles->Get(pwmGenerator);
172 if (port == nullptr) {
173 *status = HAL_HANDLE_ERROR;
174 return;
175 }
176 int32_t id = *port;
177 SimDigitalPWMData[id].pin = channel;
178}
179
180void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
181 int32_t* status) {
182 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
183 if (port == nullptr) {
184 *status = HAL_HANDLE_ERROR;
185 return;
186 }
187 if (value != 0 && value != 1) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700188 if (value != 0) {
189 value = 1;
190 }
191 }
192 if (SimDIOData[port->channel].isInput) {
193 *status = PARAMETER_OUT_OF_RANGE;
194 hal::SetLastError(status, "Cannot set output of an input channel");
195 return;
Brian Silverman8fce7482020-01-05 13:18:21 -0800196 }
197 SimDIOData[port->channel].value = value;
198}
199
200void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
201 int32_t* status) {
202 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
203 if (port == nullptr) {
204 *status = HAL_HANDLE_ERROR;
205 return;
206 }
207
208 SimDIOData[port->channel].isInput = input;
209}
210
211HAL_Bool HAL_GetDIO(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 HAL_Bool value = SimDIOData[port->channel].value;
Austin Schuh812d0d12021-11-04 20:16:48 -0700218 if (value > 1) {
219 value = 1;
220 }
221 if (value < 0) {
222 value = 0;
223 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800224 return value;
225}
226
227HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
228 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
229 if (port == nullptr) {
230 *status = HAL_HANDLE_ERROR;
231 return false;
232 }
233 HAL_Bool value = SimDIOData[port->channel].isInput;
Austin Schuh812d0d12021-11-04 20:16:48 -0700234 if (value > 1) {
235 value = 1;
236 }
237 if (value < 0) {
238 value = 0;
239 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800240 return value;
241}
242
James Kuszmaulcf324122023-01-14 14:07:17 -0800243void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLengthSeconds,
Brian Silverman8fce7482020-01-05 13:18:21 -0800244 int32_t* status) {
245 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
246 if (port == nullptr) {
247 *status = HAL_HANDLE_ERROR;
248 return;
249 }
250 // TODO (Thad) Add this
251}
252
James Kuszmaulcf324122023-01-14 14:07:17 -0800253void HAL_PulseMultiple(uint32_t channelMask, double pulseLengthSeconds,
254 int32_t* status) {
255 // TODO (Thad) Add this
256}
257
Brian Silverman8fce7482020-01-05 13:18:21 -0800258HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
259 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
260 if (port == nullptr) {
261 *status = HAL_HANDLE_ERROR;
262 return false;
263 }
264 return false;
265 // TODO (Thad) Add this
266}
267
268HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
269 return false; // TODO(Thad) Figure this out
270}
271
272void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
273 int32_t* status) {
274 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
275 if (port == nullptr) {
276 *status = HAL_HANDLE_ERROR;
277 return;
278 }
279
280 // TODO(Thad) Figure this out
281}
282
283int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
284 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
285 if (port == nullptr) {
286 *status = HAL_HANDLE_ERROR;
287 return 0;
288 }
289 return 0;
290 // TODO(Thad) Figure this out
291}
292
293void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
294 // TODO(Thad) figure this out
295}
296
297int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
298 return 0; // TODO(Thad) figure this out
299}
300} // extern "C"