blob: e6308fbb75af094c6847121676ff3788c5fe1972 [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 }
203 uint16_t pwmPeriodPower =
204 std::lround(std::log(1.0 / (16 * 1.0E-6 * rate)) / std::log(2.0));
Brian Silverman8fce7482020-01-05 13:18:21 -0800205 digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
206}
207
208void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
209 double dutyCycle, int32_t* status) {
210 auto port = digitalPWMHandles->Get(pwmGenerator);
211 if (port == nullptr) {
212 *status = HAL_HANDLE_ERROR;
213 return;
214 }
215 int32_t id = *port;
Austin Schuh812d0d12021-11-04 20:16:48 -0700216 if (dutyCycle > 1.0) {
217 dutyCycle = 1.0;
218 }
219 if (dutyCycle < 0.0) {
220 dutyCycle = 0.0;
221 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800222 double rawDutyCycle = 256.0 * dutyCycle;
Austin Schuh812d0d12021-11-04 20:16:48 -0700223 if (rawDutyCycle > 255.5) {
224 rawDutyCycle = 255.5;
225 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800226 {
227 std::scoped_lock lock(digitalPwmMutex);
228 uint16_t pwmPeriodPower = digitalSystem->readPWMPeriodPower(status);
229 if (pwmPeriodPower < 4) {
230 // The resolution of the duty cycle drops close to the highest
231 // frequencies.
232 rawDutyCycle = rawDutyCycle / std::pow(2.0, 4 - pwmPeriodPower);
233 }
234 if (id < 4)
235 digitalSystem->writePWMDutyCycleA(id, static_cast<uint8_t>(rawDutyCycle),
236 status);
237 else
238 digitalSystem->writePWMDutyCycleB(
239 id - 4, static_cast<uint8_t>(rawDutyCycle), status);
240 }
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);
258 if (id < 4)
259 digitalSystem->writePWMDutyCycleA(id, static_cast<uint8_t>(rawDutyCycle),
260 status);
261 else
262 digitalSystem->writePWMDutyCycleB(
263 id - 4, static_cast<uint8_t>(rawDutyCycle), status);
264 }
265}
266
Brian Silverman8fce7482020-01-05 13:18:21 -0800267void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
268 int32_t channel, int32_t* status) {
269 auto port = digitalPWMHandles->Get(pwmGenerator);
270 if (port == nullptr) {
271 *status = HAL_HANDLE_ERROR;
272 return;
273 }
274 int32_t id = *port;
275 if (channel >= kNumDigitalHeaders &&
276 channel <
277 kNumDigitalHeaders + kNumDigitalMXPChannels) { // If it is on the MXP
278 /* Then to write as a digital PWM channel an offset is needed to write on
279 * the correct channel
280 */
281 channel += kMXPDigitalPWMOffset;
282 }
283 digitalSystem->writePWMOutputSelect(id, channel, status);
284}
285
286void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
287 int32_t* status) {
288 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
289 if (port == nullptr) {
290 *status = HAL_HANDLE_ERROR;
291 return;
292 }
293 if (value != 0 && value != 1) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700294 if (value != 0) {
295 value = 1;
296 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800297 }
298 {
299 std::scoped_lock lock(digitalDIOMutex);
Austin Schuh812d0d12021-11-04 20:16:48 -0700300
301 tDIO::tOutputEnable currentOutputEnable =
302 digitalSystem->readOutputEnable(status);
303
304 HAL_Bool isInput = false;
305
306 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
307 isInput =
308 ((currentOutputEnable.SPIPort >> remapSPIChannel(port->channel)) &
309 1) == 0;
310 } else if (port->channel < kNumDigitalHeaders) {
311 isInput = ((currentOutputEnable.Headers >> port->channel) & 1) == 0;
312 } else {
313 isInput = ((currentOutputEnable.MXP >> remapMXPChannel(port->channel)) &
314 1) == 0;
315 }
316
317 if (isInput) {
318 *status = PARAMETER_OUT_OF_RANGE;
319 hal::SetLastError(status, "Cannot set output of an input channel");
320 return;
321 }
322
Brian Silverman8fce7482020-01-05 13:18:21 -0800323 tDIO::tDO currentDIO = digitalSystem->readDO(status);
324
325 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
326 if (value == 0) {
327 currentDIO.SPIPort =
328 currentDIO.SPIPort & ~(1u << remapSPIChannel(port->channel));
329 } else if (value == 1) {
330 currentDIO.SPIPort =
331 currentDIO.SPIPort | (1u << remapSPIChannel(port->channel));
332 }
333 } else if (port->channel < kNumDigitalHeaders) {
334 if (value == 0) {
335 currentDIO.Headers = currentDIO.Headers & ~(1u << port->channel);
336 } else if (value == 1) {
337 currentDIO.Headers = currentDIO.Headers | (1u << port->channel);
338 }
339 } else {
340 if (value == 0) {
341 currentDIO.MXP =
342 currentDIO.MXP & ~(1u << remapMXPChannel(port->channel));
343 } else if (value == 1) {
344 currentDIO.MXP =
345 currentDIO.MXP | (1u << remapMXPChannel(port->channel));
346 }
347 }
348 digitalSystem->writeDO(currentDIO, status);
349 }
350}
351
352void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
353 int32_t* status) {
354 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
355 if (port == nullptr) {
356 *status = HAL_HANDLE_ERROR;
357 return;
358 }
359 {
360 std::scoped_lock lock(digitalDIOMutex);
361 tDIO::tOutputEnable currentDIO = digitalSystem->readOutputEnable(status);
362
363 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
364 if (input) {
365 currentDIO.SPIPort =
366 currentDIO.SPIPort & ~(1u << remapSPIChannel(port->channel));
367 } else {
368 currentDIO.SPIPort =
369 currentDIO.SPIPort | (1u << remapSPIChannel(port->channel));
370 }
371 } else if (port->channel < kNumDigitalHeaders) {
372 if (input) {
373 currentDIO.Headers = currentDIO.Headers & ~(1u << port->channel);
374 } else {
375 currentDIO.Headers = currentDIO.Headers | (1u << port->channel);
376 }
377 } else {
378 if (input) {
379 currentDIO.MXP =
380 currentDIO.MXP & ~(1u << remapMXPChannel(port->channel));
381 } else {
382 currentDIO.MXP =
383 currentDIO.MXP | (1u << remapMXPChannel(port->channel));
384 }
385 }
386 digitalSystem->writeOutputEnable(currentDIO, status);
387 }
388}
389
390HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status) {
391 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
392 if (port == nullptr) {
393 *status = HAL_HANDLE_ERROR;
394 return false;
395 }
396 tDIO::tDI currentDIO = digitalSystem->readDI(status);
397 // Shift 00000001 over channel-1 places.
398 // AND it against the currentDIO
399 // if it == 0, then return false
400 // else return true
401
402 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
403 return ((currentDIO.SPIPort >> remapSPIChannel(port->channel)) & 1) != 0;
404 } else if (port->channel < kNumDigitalHeaders) {
405 return ((currentDIO.Headers >> port->channel) & 1) != 0;
406 } else {
407 return ((currentDIO.MXP >> remapMXPChannel(port->channel)) & 1) != 0;
408 }
409}
410
411HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status) {
412 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
413 if (port == nullptr) {
414 *status = HAL_HANDLE_ERROR;
415 return false;
416 }
417 tDIO::tOutputEnable currentOutputEnable =
418 digitalSystem->readOutputEnable(status);
419 // Shift 00000001 over port->channel-1 places.
420 // AND it against the currentOutputEnable
421 // if it == 0, then return false
422 // else return true
423
424 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
425 return ((currentOutputEnable.SPIPort >> remapSPIChannel(port->channel)) &
Austin Schuh812d0d12021-11-04 20:16:48 -0700426 1) == 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800427 } else if (port->channel < kNumDigitalHeaders) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700428 return ((currentOutputEnable.Headers >> port->channel) & 1) == 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800429 } else {
Austin Schuh812d0d12021-11-04 20:16:48 -0700430 return ((currentOutputEnable.MXP >> remapMXPChannel(port->channel)) & 1) ==
Brian Silverman8fce7482020-01-05 13:18:21 -0800431 0;
432 }
433}
434
James Kuszmaulcf324122023-01-14 14:07:17 -0800435void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLengthSeconds,
Brian Silverman8fce7482020-01-05 13:18:21 -0800436 int32_t* status) {
437 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
438 if (port == nullptr) {
439 *status = HAL_HANDLE_ERROR;
440 return;
441 }
James Kuszmaulcf324122023-01-14 14:07:17 -0800442
443 uint32_t pulseLengthMicroseconds =
444 static_cast<uint32_t>(pulseLengthSeconds * 1e6);
445
446 if (pulseLengthMicroseconds <= 0 || pulseLengthMicroseconds > 0xFFFF) {
447 *status = PARAMETER_OUT_OF_RANGE;
448 hal::SetLastError(status,
449 "Length must be between 1 and 65535 microseconds");
450 return;
451 }
452
Brian Silverman8fce7482020-01-05 13:18:21 -0800453 tDIO::tPulse pulse;
454
455 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
456 pulse.SPIPort = 1u << remapSPIChannel(port->channel);
457 } else if (port->channel < kNumDigitalHeaders) {
458 pulse.Headers = 1u << port->channel;
459 } else {
460 pulse.MXP = 1u << remapMXPChannel(port->channel);
461 }
462
463 digitalSystem->writePulseLength(
James Kuszmaulcf324122023-01-14 14:07:17 -0800464 static_cast<uint16_t>(pulseLengthMicroseconds), status);
465 digitalSystem->writePulse(pulse, status);
466}
467
468void HAL_PulseMultiple(uint32_t channelMask, double pulseLengthSeconds,
469 int32_t* status) {
470 uint32_t pulseLengthMicroseconds =
471 static_cast<uint32_t>(pulseLengthSeconds * 1e6);
472
473 if (pulseLengthMicroseconds <= 0 || pulseLengthMicroseconds > 0xFFFF) {
474 *status = PARAMETER_OUT_OF_RANGE;
475 hal::SetLastError(status,
476 "Length must be between 1 and 65535 microseconds");
477 return;
478 }
479
480 tDIO::tPulse pulse;
481 pulse.Headers = channelMask & 0x2FF;
482 pulse.MXP = (channelMask & 0xFFFF) >> 10;
483 pulse.SPIPort = (channelMask & 0x1F) >> 26;
484
485 digitalSystem->writePulseLength(
486 static_cast<uint16_t>(pulseLengthMicroseconds), status);
Brian Silverman8fce7482020-01-05 13:18:21 -0800487 digitalSystem->writePulse(pulse, status);
488}
489
490HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status) {
491 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
492 if (port == nullptr) {
493 *status = HAL_HANDLE_ERROR;
494 return false;
495 }
496 tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
497
498 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
499 return (pulseRegister.SPIPort & (1 << remapSPIChannel(port->channel))) != 0;
500 } else if (port->channel < kNumDigitalHeaders) {
501 return (pulseRegister.Headers & (1 << port->channel)) != 0;
502 } else {
503 return (pulseRegister.MXP & (1 << remapMXPChannel(port->channel))) != 0;
504 }
505}
506
507HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
508 initializeDigital(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700509 if (*status != 0) {
510 return false;
511 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800512 tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
513 return pulseRegister.Headers != 0 && pulseRegister.MXP != 0 &&
514 pulseRegister.SPIPort != 0;
515}
516
517void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
518 int32_t* status) {
519 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
520 if (port == nullptr) {
521 *status = HAL_HANDLE_ERROR;
522 return;
523 }
524
525 std::scoped_lock lock(digitalDIOMutex);
526 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
527 // Channels 10-15 are SPI channels, so subtract our MXP channels
528 digitalSystem->writeFilterSelectHdr(port->channel - kNumDigitalMXPChannels,
529 filterIndex, status);
530 } else if (port->channel < kNumDigitalHeaders) {
531 digitalSystem->writeFilterSelectHdr(port->channel, filterIndex, status);
532 } else {
533 digitalSystem->writeFilterSelectMXP(remapMXPChannel(port->channel),
534 filterIndex, status);
535 }
536}
537
538int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status) {
539 auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
540 if (port == nullptr) {
541 *status = HAL_HANDLE_ERROR;
542 return 0;
543 }
544
545 std::scoped_lock lock(digitalDIOMutex);
546 if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
547 // Channels 10-15 are SPI channels, so subtract our MXP channels
548 return digitalSystem->readFilterSelectHdr(
549 port->channel - kNumDigitalMXPChannels, status);
550 } else if (port->channel < kNumDigitalHeaders) {
551 return digitalSystem->readFilterSelectHdr(port->channel, status);
552 } else {
553 return digitalSystem->readFilterSelectMXP(remapMXPChannel(port->channel),
554 status);
555 }
556}
557
558void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
559 initializeDigital(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700560 if (*status != 0) {
561 return;
562 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800563 std::scoped_lock lock(digitalDIOMutex);
564 digitalSystem->writeFilterPeriodHdr(filterIndex, value, status);
565 if (*status == 0) {
566 digitalSystem->writeFilterPeriodMXP(filterIndex, value, status);
567 }
568}
569
570int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
571 initializeDigital(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700572 if (*status != 0) {
573 return 0;
574 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800575 uint32_t hdrPeriod = 0;
576 uint32_t mxpPeriod = 0;
577 {
578 std::scoped_lock lock(digitalDIOMutex);
579 hdrPeriod = digitalSystem->readFilterPeriodHdr(filterIndex, status);
580 if (*status == 0) {
581 mxpPeriod = digitalSystem->readFilterPeriodMXP(filterIndex, status);
582 }
583 }
584 if (hdrPeriod != mxpPeriod) {
585 *status = NiFpga_Status_SoftwareFault;
586 return -1;
587 }
588 return hdrPeriod;
589}
590
591} // extern "C"