blob: d75f32b9c9f5689353e778400adfa8787f7dc3e9 [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
7#include <cmath>
Austin Schuh812d0d12021-11-04 20:16:48 -07008#include <cstdio>
Brian Silverman8fce7482020-01-05 13:18:21 -08009#include <thread>
10
Brian Silverman8fce7482020-01-05 13:18:21 -080011#include "DigitalInternal.h"
12#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070013#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080014#include "PortsInternal.h"
15#include "hal/cpp/fpga_clock.h"
16#include "hal/handles/HandlesInternal.h"
17#include "hal/handles/LimitedHandleResource.h"
18
19using namespace hal;
20
21// Create a mutex to protect changes to the DO PWM config
22static wpi::mutex digitalPwmMutex;
23
24static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
25 kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>*
26 digitalPWMHandles;
27
Austin Schuh812d0d12021-11-04 20:16:48 -070028namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080029void InitializeDIO() {
30 static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
31 kNumDigitalPWMOutputs,
32 HAL_HandleEnum::DigitalPWM>
33 dpH;
34 digitalPWMHandles = &dpH;
35}
Austin Schuh812d0d12021-11-04 20:16:48 -070036} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080037
38extern "C" {
39
40HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
Austin Schuh812d0d12021-11-04 20:16:48 -070041 HAL_Bool input,
42 const char* allocationLocation,
43 int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -080044 hal::init::CheckInit();
45 initializeDigital(status);
46
Austin Schuh812d0d12021-11-04 20:16:48 -070047 if (*status != 0) {
Brian Silverman8fce7482020-01-05 13:18:21 -080048 return HAL_kInvalidHandle;
49 }
50
Austin Schuh812d0d12021-11-04 20:16:48 -070051 int16_t channel = getPortHandleChannel(portHandle);
52 if (channel == InvalidHandleIndex || channel >= kNumDigitalChannels) {
53 *status = RESOURCE_OUT_OF_RANGE;
54 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
55 kNumDigitalChannels, channel);
Brian Silverman8fce7482020-01-05 13:18:21 -080056 return HAL_kInvalidHandle;
57 }
58
Austin Schuh812d0d12021-11-04 20:16:48 -070059 HAL_DigitalHandle handle;
60
61 auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO,
62 &handle, status);
63
64 if (*status != 0) {
65 if (port) {
66 hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
67 port->previousAllocation);
68 } else {
69 hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
70 kNumDigitalChannels, channel);
71 }
72 return HAL_kInvalidHandle; // failed to allocate. Pass error back.
73 }
74
Brian Silverman8fce7482020-01-05 13:18:21 -080075 port->channel = static_cast<uint8_t>(channel);
76
77 std::scoped_lock lock(digitalDIOMutex);
78
79 tDIO::tOutputEnable outputEnable = digitalSystem->readOutputEnable(status);
80
81 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
82 if (!getPortHandleSPIEnable(portHandle)) {
83 // if this flag is not set, we actually want DIO.
84 uint32_t bitToSet = 1u << remapSPIChannel(port->channel);
85
86 uint16_t specialFunctions = spiSystem->readEnableDIO(status);
87 // Set the field to enable SPI DIO
88 spiSystem->writeEnableDIO(specialFunctions | bitToSet, status);
89
90 if (input) {
91 outputEnable.SPIPort =
92 outputEnable.SPIPort & (~bitToSet); // clear the field for read
93 } else {
94 outputEnable.SPIPort =
95 outputEnable.SPIPort | bitToSet; // set the bits for write
96 }
97 }
98 } else if (port->channel < kNumDigitalHeaders) {
99 uint32_t bitToSet = 1u << port->channel;
100 if (input) {
101 outputEnable.Headers =
102 outputEnable.Headers & (~bitToSet); // clear the bit for read
103 } else {
104 outputEnable.Headers =
105 outputEnable.Headers | bitToSet; // set the bit for write
106 }
107 } else {
108 uint32_t bitToSet = 1u << remapMXPChannel(port->channel);
109
110 uint16_t specialFunctions =
111 digitalSystem->readEnableMXPSpecialFunction(status);
112 digitalSystem->writeEnableMXPSpecialFunction(specialFunctions & ~bitToSet,
113 status);
114
115 if (input) {
116 outputEnable.MXP =
117 outputEnable.MXP & (~bitToSet); // clear the bit for read
118 } else {
119 outputEnable.MXP = outputEnable.MXP | bitToSet; // set the bit for write
120 }
121 }
122
123 digitalSystem->writeOutputEnable(outputEnable, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700124 port->previousAllocation = allocationLocation ? allocationLocation : "";
Brian Silverman8fce7482020-01-05 13:18:21 -0800125
126 return handle;
127}
128
129HAL_Bool HAL_CheckDIOChannel(int32_t channel) {
130 return channel < kNumDigitalChannels && channel >= 0;
131}
132
133void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
134 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
135 // no status, so no need to check for a proper free.
James Kuszmaulcf324122023-01-14 14:07:17 -0800136 if (port == nullptr) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700137 return;
James Kuszmaulcf324122023-01-14 14:07:17 -0800138 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800139 digitalChannelHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
140
141 // Wait for no other object to hold this handle.
142 auto start = hal::fpga_clock::now();
143 while (port.use_count() != 1) {
144 auto current = hal::fpga_clock::now();
145 if (start + std::chrono::seconds(1) < current) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700146 std::puts("DIO handle free timeout");
147 std::fflush(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800148 break;
149 }
150 std::this_thread::yield();
151 }
152
153 int32_t status = 0;
154 std::scoped_lock lock(digitalDIOMutex);
155 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
156 // Unset the SPI flag
157 int32_t bitToUnset = 1 << remapSPIChannel(port->channel);
158 uint16_t specialFunctions = spiSystem->readEnableDIO(&status);
159 spiSystem->writeEnableDIO(specialFunctions & ~bitToUnset, &status);
160 } else if (port->channel >= kNumDigitalHeaders) {
161 // Unset the MXP flag
162 uint32_t bitToUnset = 1u << remapMXPChannel(port->channel);
163
164 uint16_t specialFunctions =
165 digitalSystem->readEnableMXPSpecialFunction(&status);
166 digitalSystem->writeEnableMXPSpecialFunction(specialFunctions | bitToUnset,
167 &status);
168 }
169}
170
171void HAL_SetDIOSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
172}
173
174HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status) {
175 auto handle = digitalPWMHandles->Allocate();
176 if (handle == HAL_kInvalidHandle) {
177 *status = NO_AVAILABLE_RESOURCES;
178 return HAL_kInvalidHandle;
179 }
180
181 auto id = digitalPWMHandles->Get(handle);
182 if (id == nullptr) { // would only occur on thread issue.
183 *status = HAL_HANDLE_ERROR;
184 return HAL_kInvalidHandle;
185 }
186 *id = static_cast<uint8_t>(getHandleIndex(handle));
187
188 return handle;
189}
190
191void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status) {
192 digitalPWMHandles->Free(pwmGenerator);
193}
194
195void HAL_SetDigitalPWMRate(double rate, int32_t* status) {
196 // Currently rounding in the log rate domain... heavy weight toward picking a
197 // higher freq.
198 // TODO: Round in the linear rate domain.
199 initializeDigital(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700200 if (*status != 0) {
201 return;
202 }
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800203 uint16_t pwmPeriodPower = std::lround(std::log2(1.0 / (16 * 1.0E-6 * rate)));
Brian Silverman8fce7482020-01-05 13:18:21 -0800204 digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
205}
206
207void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
208 double dutyCycle, int32_t* status) {
209 auto port = digitalPWMHandles->Get(pwmGenerator);
210 if (port == nullptr) {
211 *status = HAL_HANDLE_ERROR;
212 return;
213 }
214 int32_t id = *port;
Austin Schuh812d0d12021-11-04 20:16:48 -0700215 if (dutyCycle > 1.0) {
216 dutyCycle = 1.0;
217 }
218 if (dutyCycle < 0.0) {
219 dutyCycle = 0.0;
220 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800221 double rawDutyCycle = 256.0 * dutyCycle;
Austin Schuh812d0d12021-11-04 20:16:48 -0700222 if (rawDutyCycle > 255.5) {
223 rawDutyCycle = 255.5;
224 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800225 {
226 std::scoped_lock lock(digitalPwmMutex);
227 uint16_t pwmPeriodPower = digitalSystem->readPWMPeriodPower(status);
228 if (pwmPeriodPower < 4) {
229 // The resolution of the duty cycle drops close to the highest
230 // frequencies.
231 rawDutyCycle = rawDutyCycle / std::pow(2.0, 4 - pwmPeriodPower);
232 }
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800233 if (id < 4) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800234 digitalSystem->writePWMDutyCycleA(id, static_cast<uint8_t>(rawDutyCycle),
235 status);
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800236 } else {
Brian Silverman8fce7482020-01-05 13:18:21 -0800237 digitalSystem->writePWMDutyCycleB(
238 id - 4, static_cast<uint8_t>(rawDutyCycle), status);
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800239 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800240 }
241}
242
James Kuszmaulcf324122023-01-14 14:07:17 -0800243void HAL_SetDigitalPWMPPS(HAL_DigitalPWMHandle pwmGenerator, double dutyCycle,
244 int32_t* status) {
245 auto port = digitalPWMHandles->Get(pwmGenerator);
246 if (port == nullptr) {
247 *status = HAL_HANDLE_ERROR;
248 return;
249 }
250 int32_t id = *port;
251 digitalSystem->writePWMPeriodPower(0xffff, status);
252 double rawDutyCycle = 31.0 * dutyCycle;
253 if (rawDutyCycle > 30.5) {
254 rawDutyCycle = 30.5;
255 }
256 {
257 std::scoped_lock lock(digitalPwmMutex);
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800258 if (id < 4) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800259 digitalSystem->writePWMDutyCycleA(id, static_cast<uint8_t>(rawDutyCycle),
260 status);
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800261 } else {
James Kuszmaulcf324122023-01-14 14:07:17 -0800262 digitalSystem->writePWMDutyCycleB(
263 id - 4, static_cast<uint8_t>(rawDutyCycle), status);
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800264 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800265 }
266}
267
Brian Silverman8fce7482020-01-05 13:18:21 -0800268void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
269 int32_t channel, int32_t* status) {
270 auto port = digitalPWMHandles->Get(pwmGenerator);
271 if (port == nullptr) {
272 *status = HAL_HANDLE_ERROR;
273 return;
274 }
275 int32_t id = *port;
276 if (channel >= kNumDigitalHeaders &&
277 channel <
278 kNumDigitalHeaders + kNumDigitalMXPChannels) { // If it is on the MXP
279 /* Then to write as a digital PWM channel an offset is needed to write on
280 * the correct channel
281 */
282 channel += kMXPDigitalPWMOffset;
283 }
284 digitalSystem->writePWMOutputSelect(id, channel, status);
285}
286
287void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
288 int32_t* status) {
289 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
290 if (port == nullptr) {
291 *status = HAL_HANDLE_ERROR;
292 return;
293 }
294 if (value != 0 && value != 1) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700295 if (value != 0) {
296 value = 1;
297 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800298 }
299 {
300 std::scoped_lock lock(digitalDIOMutex);
Austin Schuh812d0d12021-11-04 20:16:48 -0700301
302 tDIO::tOutputEnable currentOutputEnable =
303 digitalSystem->readOutputEnable(status);
304
305 HAL_Bool isInput = false;
306
307 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
308 isInput =
309 ((currentOutputEnable.SPIPort >> remapSPIChannel(port->channel)) &
310 1) == 0;
311 } else if (port->channel < kNumDigitalHeaders) {
312 isInput = ((currentOutputEnable.Headers >> port->channel) & 1) == 0;
313 } else {
314 isInput = ((currentOutputEnable.MXP >> remapMXPChannel(port->channel)) &
315 1) == 0;
316 }
317
318 if (isInput) {
319 *status = PARAMETER_OUT_OF_RANGE;
320 hal::SetLastError(status, "Cannot set output of an input channel");
321 return;
322 }
323
Brian Silverman8fce7482020-01-05 13:18:21 -0800324 tDIO::tDO currentDIO = digitalSystem->readDO(status);
325
326 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
327 if (value == 0) {
328 currentDIO.SPIPort =
329 currentDIO.SPIPort & ~(1u << remapSPIChannel(port->channel));
330 } else if (value == 1) {
331 currentDIO.SPIPort =
332 currentDIO.SPIPort | (1u << remapSPIChannel(port->channel));
333 }
334 } else if (port->channel < kNumDigitalHeaders) {
335 if (value == 0) {
336 currentDIO.Headers = currentDIO.Headers & ~(1u << port->channel);
337 } else if (value == 1) {
338 currentDIO.Headers = currentDIO.Headers | (1u << port->channel);
339 }
340 } else {
341 if (value == 0) {
342 currentDIO.MXP =
343 currentDIO.MXP & ~(1u << remapMXPChannel(port->channel));
344 } else if (value == 1) {
345 currentDIO.MXP =
346 currentDIO.MXP | (1u << remapMXPChannel(port->channel));
347 }
348 }
349 digitalSystem->writeDO(currentDIO, status);
350 }
351}
352
353void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
354 int32_t* status) {
355 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
356 if (port == nullptr) {
357 *status = HAL_HANDLE_ERROR;
358 return;
359 }
360 {
361 std::scoped_lock lock(digitalDIOMutex);
362 tDIO::tOutputEnable currentDIO = digitalSystem->readOutputEnable(status);
363
364 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
365 if (input) {
366 currentDIO.SPIPort =
367 currentDIO.SPIPort & ~(1u << remapSPIChannel(port->channel));
368 } else {
369 currentDIO.SPIPort =
370 currentDIO.SPIPort | (1u << remapSPIChannel(port->channel));
371 }
372 } else if (port->channel < kNumDigitalHeaders) {
373 if (input) {
374 currentDIO.Headers = currentDIO.Headers & ~(1u << port->channel);
375 } else {
376 currentDIO.Headers = currentDIO.Headers | (1u << port->channel);
377 }
378 } else {
379 if (input) {
380 currentDIO.MXP =
381 currentDIO.MXP & ~(1u << remapMXPChannel(port->channel));
382 } else {
383 currentDIO.MXP =
384 currentDIO.MXP | (1u << remapMXPChannel(port->channel));
385 }
386 }
387 digitalSystem->writeOutputEnable(currentDIO, status);
388 }
389}
390
391HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
392 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
393 if (port == nullptr) {
394 *status = HAL_HANDLE_ERROR;
395 return false;
396 }
397 tDIO::tDI currentDIO = digitalSystem->readDI(status);
398 // Shift 00000001 over channel-1 places.
399 // AND it against the currentDIO
400 // if it == 0, then return false
401 // else return true
402
403 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
404 return ((currentDIO.SPIPort >> remapSPIChannel(port->channel)) & 1) != 0;
405 } else if (port->channel < kNumDigitalHeaders) {
406 return ((currentDIO.Headers >> port->channel) & 1) != 0;
407 } else {
408 return ((currentDIO.MXP >> remapMXPChannel(port->channel)) & 1) != 0;
409 }
410}
411
412HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
413 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
414 if (port == nullptr) {
415 *status = HAL_HANDLE_ERROR;
416 return false;
417 }
418 tDIO::tOutputEnable currentOutputEnable =
419 digitalSystem->readOutputEnable(status);
420 // Shift 00000001 over port->channel-1 places.
421 // AND it against the currentOutputEnable
422 // if it == 0, then return false
423 // else return true
424
425 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
426 return ((currentOutputEnable.SPIPort >> remapSPIChannel(port->channel)) &
Austin Schuh812d0d12021-11-04 20:16:48 -0700427 1) == 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800428 } else if (port->channel < kNumDigitalHeaders) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700429 return ((currentOutputEnable.Headers >> port->channel) & 1) == 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800430 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700431 return ((currentOutputEnable.MXP >> remapMXPChannel(port->channel)) & 1) ==
Brian Silverman8fce7482020-01-05 13:18:21 -0800432 0;
433 }
434}
435
James Kuszmaulcf324122023-01-14 14:07:17 -0800436void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLengthSeconds,
Brian Silverman8fce7482020-01-05 13:18:21 -0800437 int32_t* status) {
438 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
439 if (port == nullptr) {
440 *status = HAL_HANDLE_ERROR;
441 return;
442 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800443
444 uint32_t pulseLengthMicroseconds =
445 static_cast<uint32_t>(pulseLengthSeconds * 1e6);
446
447 if (pulseLengthMicroseconds <= 0 || pulseLengthMicroseconds > 0xFFFF) {
448 *status = PARAMETER_OUT_OF_RANGE;
449 hal::SetLastError(status,
450 "Length must be between 1 and 65535 microseconds");
451 return;
452 }
453
Brian Silverman8fce7482020-01-05 13:18:21 -0800454 tDIO::tPulse pulse;
455
456 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
457 pulse.SPIPort = 1u << remapSPIChannel(port->channel);
458 } else if (port->channel < kNumDigitalHeaders) {
459 pulse.Headers = 1u << port->channel;
460 } else {
461 pulse.MXP = 1u << remapMXPChannel(port->channel);
462 }
463
464 digitalSystem->writePulseLength(
James Kuszmaulcf324122023-01-14 14:07:17 -0800465 static_cast<uint16_t>(pulseLengthMicroseconds), status);
466 digitalSystem->writePulse(pulse, status);
467}
468
469void HAL_PulseMultiple(uint32_t channelMask, double pulseLengthSeconds,
470 int32_t* status) {
471 uint32_t pulseLengthMicroseconds =
472 static_cast<uint32_t>(pulseLengthSeconds * 1e6);
473
474 if (pulseLengthMicroseconds <= 0 || pulseLengthMicroseconds > 0xFFFF) {
475 *status = PARAMETER_OUT_OF_RANGE;
476 hal::SetLastError(status,
477 "Length must be between 1 and 65535 microseconds");
478 return;
479 }
480
481 tDIO::tPulse pulse;
482 pulse.Headers = channelMask & 0x2FF;
483 pulse.MXP = (channelMask & 0xFFFF) >> 10;
484 pulse.SPIPort = (channelMask & 0x1F) >> 26;
485
486 digitalSystem->writePulseLength(
487 static_cast<uint16_t>(pulseLengthMicroseconds), status);
Brian Silverman8fce7482020-01-05 13:18:21 -0800488 digitalSystem->writePulse(pulse, status);
489}
490
491HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
492 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
493 if (port == nullptr) {
494 *status = HAL_HANDLE_ERROR;
495 return false;
496 }
497 tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
498
499 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
500 return (pulseRegister.SPIPort & (1 << remapSPIChannel(port->channel))) != 0;
501 } else if (port->channel < kNumDigitalHeaders) {
502 return (pulseRegister.Headers & (1 << port->channel)) != 0;
503 } else {
504 return (pulseRegister.MXP & (1 << remapMXPChannel(port->channel))) != 0;
505 }
506}
507
508HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
509 initializeDigital(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700510 if (*status != 0) {
511 return false;
512 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800513 tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
514 return pulseRegister.Headers != 0 && pulseRegister.MXP != 0 &&
515 pulseRegister.SPIPort != 0;
516}
517
518void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
519 int32_t* status) {
520 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
521 if (port == nullptr) {
522 *status = HAL_HANDLE_ERROR;
523 return;
524 }
525
526 std::scoped_lock lock(digitalDIOMutex);
527 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
528 // Channels 10-15 are SPI channels, so subtract our MXP channels
529 digitalSystem->writeFilterSelectHdr(port->channel - kNumDigitalMXPChannels,
530 filterIndex, status);
531 } else if (port->channel < kNumDigitalHeaders) {
532 digitalSystem->writeFilterSelectHdr(port->channel, filterIndex, status);
533 } else {
534 digitalSystem->writeFilterSelectMXP(remapMXPChannel(port->channel),
535 filterIndex, status);
536 }
537}
538
539int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
540 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
541 if (port == nullptr) {
542 *status = HAL_HANDLE_ERROR;
543 return 0;
544 }
545
546 std::scoped_lock lock(digitalDIOMutex);
547 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
548 // Channels 10-15 are SPI channels, so subtract our MXP channels
549 return digitalSystem->readFilterSelectHdr(
550 port->channel - kNumDigitalMXPChannels, status);
551 } else if (port->channel < kNumDigitalHeaders) {
552 return digitalSystem->readFilterSelectHdr(port->channel, status);
553 } else {
554 return digitalSystem->readFilterSelectMXP(remapMXPChannel(port->channel),
555 status);
556 }
557}
558
559void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
560 initializeDigital(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700561 if (*status != 0) {
562 return;
563 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800564 std::scoped_lock lock(digitalDIOMutex);
565 digitalSystem->writeFilterPeriodHdr(filterIndex, value, status);
566 if (*status == 0) {
567 digitalSystem->writeFilterPeriodMXP(filterIndex, value, status);
568 }
569}
570
571int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
572 initializeDigital(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700573 if (*status != 0) {
574 return 0;
575 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800576 uint32_t hdrPeriod = 0;
577 uint32_t mxpPeriod = 0;
578 {
579 std::scoped_lock lock(digitalDIOMutex);
580 hdrPeriod = digitalSystem->readFilterPeriodHdr(filterIndex, status);
581 if (*status == 0) {
582 mxpPeriod = digitalSystem->readFilterPeriodMXP(filterIndex, status);
583 }
584 }
585 if (hdrPeriod != mxpPeriod) {
586 *status = NiFpga_Status_SoftwareFault;
587 return -1;
588 }
589 return hdrPeriod;
590}
591
592} // extern "C"