blob: f7d8b087207ed465708bfe358fc74fa554d785fd [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/DMA.h"
6
7#include <array>
8#include <cstddef>
9#include <cstring>
10#include <memory>
11#include <type_traits>
12
13#include "AnalogInternal.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070014#include "ConstantsInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080015#include "DigitalInternal.h"
16#include "EncoderInternal.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070017#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080018#include "PortsInternal.h"
19#include "hal/AnalogAccumulator.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080020#include "hal/AnalogGyro.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080021#include "hal/AnalogInput.h"
22#include "hal/ChipObject.h"
23#include "hal/Errors.h"
24#include "hal/HALBase.h"
25#include "hal/handles/HandlesInternal.h"
26#include "hal/handles/LimitedHandleResource.h"
27#include "hal/handles/UnlimitedHandleResource.h"
28
29using namespace hal;
30
31static_assert(std::is_standard_layout_v<HAL_DMASample>,
32 "HAL_DMASample must have standard layout");
33
34namespace {
35
36struct DMA {
37 std::unique_ptr<tDMAManager> manager;
38 std::unique_ptr<tDMA> aDMA;
39
40 HAL_DMASample captureStore;
41};
42} // namespace
43
44static constexpr size_t kChannelSize[22] = {2, 2, 4, 4, 2, 2, 4, 4, 3, 3, 2,
45 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};
46
47enum DMAOffsetConstants {
48 kEnable_AI0_Low = 0,
49 kEnable_AI0_High = 1,
50 kEnable_AIAveraged0_Low = 2,
51 kEnable_AIAveraged0_High = 3,
52 kEnable_AI1_Low = 4,
53 kEnable_AI1_High = 5,
54 kEnable_AIAveraged1_Low = 6,
55 kEnable_AIAveraged1_High = 7,
56 kEnable_Accumulator0 = 8,
57 kEnable_Accumulator1 = 9,
58 kEnable_DI = 10,
59 kEnable_AnalogTriggers = 11,
60 kEnable_Counters_Low = 12,
61 kEnable_Counters_High = 13,
62 kEnable_CounterTimers_Low = 14,
63 kEnable_CounterTimers_High = 15,
64 kEnable_Encoders_Low = 16,
65 kEnable_Encoders_High = 17,
66 kEnable_EncoderTimers_Low = 18,
67 kEnable_EncoderTimers_High = 19,
68 kEnable_DutyCycle_Low = 20,
69 kEnable_DutyCycle_High = 21,
70};
71
72static hal::LimitedHandleResource<HAL_DMAHandle, DMA, 1, HAL_HandleEnum::DMA>*
73 dmaHandles;
74
Austin Schuh812d0d12021-11-04 20:16:48 -070075namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080076void InitializeDMA() {
77 static hal::LimitedHandleResource<HAL_DMAHandle, DMA, 1, HAL_HandleEnum::DMA>
78 dH;
79 dmaHandles = &dH;
80}
Austin Schuh812d0d12021-11-04 20:16:48 -070081} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080082
83extern "C" {
84
85HAL_DMAHandle HAL_InitializeDMA(int32_t* status) {
86 HAL_Handle handle = dmaHandles->Allocate();
87 if (handle == HAL_kInvalidHandle) {
88 *status = NO_AVAILABLE_RESOURCES;
89 return HAL_kInvalidHandle;
90 }
91
92 auto dma = dmaHandles->Get(handle);
93
94 if (!dma) {
95 // Can only happen on thread error
96 *status = HAL_HANDLE_ERROR;
97 return HAL_kInvalidHandle;
98 }
99
100 // Manager does not get created until DMA is started
101 dma->aDMA.reset(tDMA::create(status));
102 if (*status != 0) {
103 dmaHandles->Free(handle);
104 return HAL_kInvalidHandle;
105 }
106
Austin Schuh812d0d12021-11-04 20:16:48 -0700107 std::memset(&dma->captureStore, 0, sizeof(dma->captureStore));
108
109 tDMA::tConfig config;
110 std::memset(&config, 0, sizeof(config));
111 config.Pause = true;
112 dma->aDMA->writeConfig(config, status);
113
114 dma->aDMA->writeRate(1, status);
115
116 tDMA::tExternalTriggers newTrigger;
117 std::memset(&newTrigger, 0, sizeof(newTrigger));
118 for (unsigned char reg = 0; reg < tDMA::kNumExternalTriggersRegisters;
119 reg++) {
120 for (unsigned char bit = 0; bit < tDMA::kNumExternalTriggersElements;
121 bit++) {
122 dma->aDMA->writeExternalTriggers(reg, bit, newTrigger, status);
123 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800124 }
125
Brian Silverman8fce7482020-01-05 13:18:21 -0800126 return handle;
127}
128
129void HAL_FreeDMA(HAL_DMAHandle handle) {
130 auto dma = dmaHandles->Get(handle);
131 dmaHandles->Free(handle);
132
Austin Schuh812d0d12021-11-04 20:16:48 -0700133 if (!dma)
134 return;
Brian Silverman8fce7482020-01-05 13:18:21 -0800135
136 int32_t status = 0;
137 if (dma->manager) {
138 dma->manager->stop(&status);
139 }
140}
141
142void HAL_SetDMAPause(HAL_DMAHandle handle, HAL_Bool pause, int32_t* status) {
143 auto dma = dmaHandles->Get(handle);
144 if (!dma) {
145 *status = HAL_HANDLE_ERROR;
146 return;
147 }
148
Austin Schuh812d0d12021-11-04 20:16:48 -0700149 if (!dma->manager) {
150 *status = HAL_INVALID_DMA_STATE;
151 return;
152 }
153
Brian Silverman8fce7482020-01-05 13:18:21 -0800154 dma->aDMA->writeConfig_Pause(pause, status);
155}
Austin Schuh812d0d12021-11-04 20:16:48 -0700156
157void HAL_SetDMATimedTrigger(HAL_DMAHandle handle, double seconds,
158 int32_t* status) {
159 constexpr double baseMultipler = kSystemClockTicksPerMicrosecond * 1000000;
160 uint32_t cycles = static_cast<uint32_t>(baseMultipler * seconds);
161 HAL_SetDMATimedTriggerCycles(handle, cycles, status);
162}
163
164void HAL_SetDMATimedTriggerCycles(HAL_DMAHandle handle, uint32_t cycles,
165 int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800166 auto dma = dmaHandles->Get(handle);
167 if (!dma) {
168 *status = HAL_HANDLE_ERROR;
169 return;
170 }
171
Austin Schuh812d0d12021-11-04 20:16:48 -0700172 if (dma->manager) {
173 *status = HAL_INVALID_DMA_ADDITION;
174 return;
175 }
176
Brian Silverman8fce7482020-01-05 13:18:21 -0800177 if (cycles < 1) {
178 cycles = 1;
179 }
180
Austin Schuh812d0d12021-11-04 20:16:48 -0700181 dma->aDMA->writeConfig_ExternalClock(false, status);
182 if (*status != 0) {
183 return;
184 }
185
186 dma->aDMA->writeRate(cycles, status);
Brian Silverman8fce7482020-01-05 13:18:21 -0800187}
188
189void HAL_AddDMAEncoder(HAL_DMAHandle handle, HAL_EncoderHandle encoderHandle,
190 int32_t* status) {
191 // Detect a counter encoder vs an actual encoder, and use the right DMA calls
192 HAL_FPGAEncoderHandle fpgaEncoderHandle = HAL_kInvalidHandle;
193 HAL_CounterHandle counterHandle = HAL_kInvalidHandle;
194
195 bool validEncoderHandle = hal::GetEncoderBaseHandle(
196 encoderHandle, &fpgaEncoderHandle, &counterHandle);
197
198 if (!validEncoderHandle) {
199 *status = HAL_HANDLE_ERROR;
200 return;
201 }
202
203 if (counterHandle != HAL_kInvalidHandle) {
204 HAL_AddDMACounter(handle, counterHandle, status);
205 return;
206 }
207
208 auto dma = dmaHandles->Get(handle);
209 if (!dma) {
210 *status = HAL_HANDLE_ERROR;
211 return;
212 }
213
214 if (dma->manager) {
215 *status = HAL_INVALID_DMA_ADDITION;
216 return;
217 }
218
219 if (getHandleType(fpgaEncoderHandle) != HAL_HandleEnum::FPGAEncoder) {
220 *status = HAL_HANDLE_ERROR;
221 return;
222 }
223
224 int32_t index = getHandleIndex(fpgaEncoderHandle);
225 if (index < 0) {
226 *status = HAL_HANDLE_ERROR;
227 return;
228 }
229
230 if (index < 4) {
231 dma->aDMA->writeConfig_Enable_Encoders_Low(true, status);
232 } else if (index < 8) {
233 dma->aDMA->writeConfig_Enable_Encoders_High(true, status);
234 } else {
235 *status = NiFpga_Status_InvalidParameter;
236 }
237}
238
239void HAL_AddDMAEncoderPeriod(HAL_DMAHandle handle,
240 HAL_EncoderHandle encoderHandle, int32_t* status) {
241 // Detect a counter encoder vs an actual encoder, and use the right DMA calls
242 HAL_FPGAEncoderHandle fpgaEncoderHandle = HAL_kInvalidHandle;
243 HAL_CounterHandle counterHandle = HAL_kInvalidHandle;
244
245 bool validEncoderHandle = hal::GetEncoderBaseHandle(
246 encoderHandle, &fpgaEncoderHandle, &counterHandle);
247
248 if (!validEncoderHandle) {
249 *status = HAL_HANDLE_ERROR;
250 return;
251 }
252
253 if (counterHandle != HAL_kInvalidHandle) {
254 HAL_AddDMACounterPeriod(handle, counterHandle, status);
255 return;
256 }
257
258 auto dma = dmaHandles->Get(handle);
259 if (!dma) {
260 *status = HAL_HANDLE_ERROR;
261 return;
262 }
263
264 if (dma->manager) {
265 *status = HAL_INVALID_DMA_ADDITION;
266 return;
267 }
268
269 if (getHandleType(fpgaEncoderHandle) != HAL_HandleEnum::FPGAEncoder) {
270 *status = HAL_HANDLE_ERROR;
271 return;
272 }
273
274 int32_t index = getHandleIndex(fpgaEncoderHandle);
275 if (index < 0) {
276 *status = HAL_HANDLE_ERROR;
277 return;
278 }
279
280 if (index < 4) {
281 dma->aDMA->writeConfig_Enable_EncoderTimers_Low(true, status);
282 } else if (index < 8) {
283 dma->aDMA->writeConfig_Enable_EncoderTimers_High(true, status);
284 } else {
285 *status = NiFpga_Status_InvalidParameter;
286 }
287}
288
289void HAL_AddDMACounter(HAL_DMAHandle handle, HAL_CounterHandle counterHandle,
290 int32_t* status) {
291 auto dma = dmaHandles->Get(handle);
292 if (!dma) {
293 *status = HAL_HANDLE_ERROR;
294 return;
295 }
296
297 if (dma->manager) {
298 *status = HAL_INVALID_DMA_ADDITION;
299 return;
300 }
301
302 if (getHandleType(counterHandle) != HAL_HandleEnum::Counter) {
303 *status = HAL_HANDLE_ERROR;
304 return;
305 }
306
307 int32_t index = getHandleIndex(counterHandle);
308 if (index < 0) {
309 *status = HAL_HANDLE_ERROR;
310 return;
311 }
312
313 if (index < 4) {
314 dma->aDMA->writeConfig_Enable_Counters_Low(true, status);
315 } else if (index < 8) {
316 dma->aDMA->writeConfig_Enable_Counters_High(true, status);
317 } else {
318 *status = NiFpga_Status_InvalidParameter;
319 }
320}
321
322void HAL_AddDMACounterPeriod(HAL_DMAHandle handle,
323 HAL_CounterHandle counterHandle, int32_t* status) {
324 auto dma = dmaHandles->Get(handle);
325 if (!dma) {
326 *status = HAL_HANDLE_ERROR;
327 return;
328 }
329
330 if (dma->manager) {
331 *status = HAL_INVALID_DMA_ADDITION;
332 return;
333 }
334
335 if (getHandleType(counterHandle) != HAL_HandleEnum::Counter) {
336 *status = HAL_HANDLE_ERROR;
337 return;
338 }
339
340 int32_t index = getHandleIndex(counterHandle);
341 if (index < 0) {
342 *status = HAL_HANDLE_ERROR;
343 return;
344 }
345
346 if (index < 4) {
347 dma->aDMA->writeConfig_Enable_CounterTimers_Low(true, status);
348 } else if (index < 8) {
349 dma->aDMA->writeConfig_Enable_CounterTimers_High(true, status);
350 } else {
351 *status = NiFpga_Status_InvalidParameter;
352 }
353}
354
355void HAL_AddDMADigitalSource(HAL_DMAHandle handle,
356 HAL_Handle digitalSourceHandle, int32_t* status) {
357 auto dma = dmaHandles->Get(handle);
358 if (!dma) {
359 *status = HAL_HANDLE_ERROR;
360 return;
361 }
362
363 if (dma->manager) {
364 *status = HAL_INVALID_DMA_ADDITION;
365 return;
366 }
367
368 if (isHandleType(digitalSourceHandle, HAL_HandleEnum::AnalogTrigger)) {
369 dma->aDMA->writeConfig_Enable_AnalogTriggers(true, status);
370 } else if (isHandleType(digitalSourceHandle, HAL_HandleEnum::DIO)) {
371 dma->aDMA->writeConfig_Enable_DI(true, status);
372 } else {
373 *status = NiFpga_Status_InvalidParameter;
374 }
375}
376
377void HAL_AddDMAAnalogInput(HAL_DMAHandle handle,
378 HAL_AnalogInputHandle aInHandle, int32_t* status) {
379 auto dma = dmaHandles->Get(handle);
380 if (!dma) {
381 *status = HAL_HANDLE_ERROR;
382 return;
383 }
384
385 if (dma->manager) {
386 *status = HAL_INVALID_DMA_ADDITION;
387 return;
388 }
389
390 if (getHandleType(aInHandle) != HAL_HandleEnum::AnalogInput) {
391 *status = HAL_HANDLE_ERROR;
392 return;
393 }
394
395 int32_t index = getHandleIndex(aInHandle);
396 if (index < 0) {
397 *status = HAL_HANDLE_ERROR;
398 return;
399 }
400
401 if (index < 4) {
402 dma->aDMA->writeConfig_Enable_AI0_Low(true, status);
403 } else if (index < 8) {
404 dma->aDMA->writeConfig_Enable_AI0_High(true, status);
405 } else {
406 *status = NiFpga_Status_InvalidParameter;
407 }
408}
409
410void HAL_AddDMADutyCycle(HAL_DMAHandle handle,
411 HAL_DutyCycleHandle dutyCycleHandle, int32_t* status) {
412 auto dma = dmaHandles->Get(handle);
413 if (!dma) {
414 *status = HAL_HANDLE_ERROR;
415 return;
416 }
417
418 if (dma->manager) {
419 *status = HAL_INVALID_DMA_ADDITION;
420 return;
421 }
422
423 if (getHandleType(dutyCycleHandle) != HAL_HandleEnum::DutyCycle) {
424 *status = HAL_HANDLE_ERROR;
425 return;
426 }
427
428 int32_t index = getHandleIndex(dutyCycleHandle);
429 if (index < 0) {
430 *status = HAL_HANDLE_ERROR;
431 return;
432 }
433
434 if (index < 4) {
435 dma->aDMA->writeConfig_Enable_DutyCycle_Low(true, status);
436 } else if (index < 8) {
437 dma->aDMA->writeConfig_Enable_DutyCycle_High(true, status);
438 } else {
439 *status = NiFpga_Status_InvalidParameter;
440 }
441}
442
443void HAL_AddDMAAveragedAnalogInput(HAL_DMAHandle handle,
444 HAL_AnalogInputHandle aInHandle,
445 int32_t* status) {
446 auto dma = dmaHandles->Get(handle);
447 if (!dma) {
448 *status = HAL_HANDLE_ERROR;
449 return;
450 }
451
452 if (dma->manager) {
453 *status = HAL_INVALID_DMA_ADDITION;
454 return;
455 }
456
457 if (getHandleType(aInHandle) != HAL_HandleEnum::AnalogInput) {
458 *status = HAL_HANDLE_ERROR;
459 return;
460 }
461
462 int32_t index = getHandleIndex(aInHandle);
463 if (index < 0) {
464 *status = HAL_HANDLE_ERROR;
465 return;
466 }
467
468 if (index < 4) {
469 dma->aDMA->writeConfig_Enable_AIAveraged0_Low(true, status);
470 } else if (index < 8) {
471 dma->aDMA->writeConfig_Enable_AIAveraged0_High(true, status);
472 } else {
473 *status = NiFpga_Status_InvalidParameter;
474 }
475}
476
477void HAL_AddDMAAnalogAccumulator(HAL_DMAHandle handle,
478 HAL_AnalogInputHandle aInHandle,
479 int32_t* status) {
480 auto dma = dmaHandles->Get(handle);
481 if (!dma) {
482 *status = HAL_HANDLE_ERROR;
483 return;
484 }
485
486 if (dma->manager) {
487 *status = HAL_INVALID_DMA_ADDITION;
488 return;
489 }
490
491 if (!HAL_IsAccumulatorChannel(aInHandle, status)) {
492 *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
493 return;
494 }
495
496 int32_t index = getHandleIndex(aInHandle);
497 if (index < 0) {
498 *status = HAL_HANDLE_ERROR;
499 return;
500 }
501
502 if (index == 0) {
503 dma->aDMA->writeConfig_Enable_Accumulator0(true, status);
504 } else if (index == 1) {
505 dma->aDMA->writeConfig_Enable_Accumulator1(true, status);
506 } else {
507 *status = NiFpga_Status_InvalidParameter;
508 }
509}
510
Austin Schuh812d0d12021-11-04 20:16:48 -0700511int32_t HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
512 HAL_Handle digitalSourceHandle,
513 HAL_AnalogTriggerType analogTriggerType,
514 HAL_Bool rising, HAL_Bool falling,
515 int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800516 auto dma = dmaHandles->Get(handle);
517 if (!dma) {
518 *status = HAL_HANDLE_ERROR;
Austin Schuh812d0d12021-11-04 20:16:48 -0700519 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800520 }
521
522 if (dma->manager) {
523 *status = HAL_INVALID_DMA_ADDITION;
Austin Schuh812d0d12021-11-04 20:16:48 -0700524 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800525 }
526
527 int index = 0;
528 auto triggerChannels = dma->captureStore.triggerChannels;
529 do {
530 if (((triggerChannels >> index) & 0x1) == 0) {
531 break;
532 }
533 index++;
534 } while (index < 8);
535
536 if (index == 8) {
537 *status = NO_AVAILABLE_RESOURCES;
Austin Schuh812d0d12021-11-04 20:16:48 -0700538 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800539 }
540
541 dma->captureStore.triggerChannels |= (1 << index);
542
543 auto channelIndex = index;
544
Austin Schuh812d0d12021-11-04 20:16:48 -0700545 dma->aDMA->writeConfig_ExternalClock(true, status);
546 if (*status != 0) {
547 return 0;
548 }
549
550 dma->aDMA->writeRate(1, status);
551 if (*status != 0) {
552 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800553 }
554
555 uint8_t pin = 0;
556 uint8_t module = 0;
557 bool analogTrigger = false;
558 bool success = remapDigitalSource(digitalSourceHandle, analogTriggerType, pin,
559 module, analogTrigger);
560
561 if (!success) {
562 *status = PARAMETER_OUT_OF_RANGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700563 hal::SetLastError(status,
564 "Digital Source unabled to be mapped properly. Likely "
565 "invalid handle passed.");
566 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800567 }
568
569 tDMA::tExternalTriggers newTrigger;
570 newTrigger.FallingEdge = falling;
571 newTrigger.RisingEdge = rising;
572 newTrigger.ExternalClockSource_AnalogTrigger = analogTrigger;
573 newTrigger.ExternalClockSource_Channel = pin;
574 newTrigger.ExternalClockSource_Module = module;
575
576 dma->aDMA->writeExternalTriggers(channelIndex / 4, channelIndex % 4,
577 newTrigger, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700578 return index;
579}
580
581void HAL_ClearDMASensors(HAL_DMAHandle handle, int32_t* status) {
582 auto dma = dmaHandles->Get(handle);
583 if (!dma) {
584 *status = HAL_HANDLE_ERROR;
585 return;
586 }
587
588 if (dma->manager) {
589 *status = HAL_INVALID_DMA_STATE;
590 return;
591 }
592
593 bool existingExternal = dma->aDMA->readConfig_ExternalClock(status);
594 if (*status != 0) {
595 return;
596 }
597
598 tDMA::tConfig config;
599 std::memset(&config, 0, sizeof(config));
600 config.Pause = true;
601 config.ExternalClock = existingExternal;
602 dma->aDMA->writeConfig(config, status);
603}
604
605void HAL_ClearDMAExternalTriggers(HAL_DMAHandle handle, int32_t* status) {
606 auto dma = dmaHandles->Get(handle);
607 if (!dma) {
608 *status = HAL_HANDLE_ERROR;
609 return;
610 }
611
612 if (dma->manager) {
613 *status = HAL_INVALID_DMA_STATE;
614 return;
615 }
616
617 dma->captureStore.triggerChannels = 0;
618 tDMA::tExternalTriggers newTrigger;
619 std::memset(&newTrigger, 0, sizeof(newTrigger));
620 for (unsigned char reg = 0; reg < tDMA::kNumExternalTriggersRegisters;
621 reg++) {
622 for (unsigned char bit = 0; bit < tDMA::kNumExternalTriggersElements;
623 bit++) {
624 dma->aDMA->writeExternalTriggers(reg, bit, newTrigger, status);
625 }
626 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800627}
628
629void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status) {
630 auto dma = dmaHandles->Get(handle);
631 if (!dma) {
632 *status = HAL_HANDLE_ERROR;
633 return;
634 }
635
636 if (dma->manager) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700637 *status = HAL_INVALID_DMA_STATE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800638 return;
639 }
640
641 tDMA::tConfig config = dma->aDMA->readConfig(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700642 if (*status != 0) {
643 return;
644 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800645
646 {
647 size_t accum_size = 0;
648#define SET_SIZE(bit) \
649 if (config.bit) { \
650 dma->captureStore.channelOffsets[k##bit] = accum_size; \
651 accum_size += kChannelSize[k##bit]; \
652 } else { \
653 dma->captureStore.channelOffsets[k##bit] = -1; \
654 }
655 SET_SIZE(Enable_AI0_Low);
656 SET_SIZE(Enable_AI0_High);
657 SET_SIZE(Enable_AIAveraged0_Low);
658 SET_SIZE(Enable_AIAveraged0_High);
659 SET_SIZE(Enable_AI1_Low);
660 SET_SIZE(Enable_AI1_High);
661 SET_SIZE(Enable_AIAveraged1_Low);
662 SET_SIZE(Enable_AIAveraged1_High);
663 SET_SIZE(Enable_Accumulator0);
664 SET_SIZE(Enable_Accumulator1);
665 SET_SIZE(Enable_DI);
666 SET_SIZE(Enable_AnalogTriggers);
667 SET_SIZE(Enable_Counters_Low);
668 SET_SIZE(Enable_Counters_High);
669 SET_SIZE(Enable_CounterTimers_Low);
670 SET_SIZE(Enable_CounterTimers_High);
671 SET_SIZE(Enable_Encoders_Low);
672 SET_SIZE(Enable_Encoders_High);
673 SET_SIZE(Enable_EncoderTimers_Low);
674 SET_SIZE(Enable_EncoderTimers_High);
675 SET_SIZE(Enable_DutyCycle_Low);
676 SET_SIZE(Enable_DutyCycle_High);
677#undef SET_SIZE
678 dma->captureStore.captureSize = accum_size + 1;
679 }
680
Austin Schuh812d0d12021-11-04 20:16:48 -0700681 uint32_t byteDepth = queueDepth * dma->captureStore.captureSize;
682
683 dma->manager = std::make_unique<tDMAManager>(g_DMA_index, byteDepth, status);
Brian Silverman8fce7482020-01-05 13:18:21 -0800684 if (*status != 0) {
685 return;
686 }
687
Austin Schuh812d0d12021-11-04 20:16:48 -0700688 dma->aDMA->writeConfig_Pause(false, status);
689
Brian Silverman8fce7482020-01-05 13:18:21 -0800690 dma->manager->start(status);
691 dma->manager->stop(status);
692 dma->manager->start(status);
693}
694
695void HAL_StopDMA(HAL_DMAHandle handle, int32_t* status) {
696 auto dma = dmaHandles->Get(handle);
697 if (!dma) {
698 *status = HAL_HANDLE_ERROR;
699 return;
700 }
701
702 if (dma->manager) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700703 dma->aDMA->writeConfig_Pause(true, status);
704 *status = 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800705 dma->manager->stop(status);
706 dma->manager = nullptr;
707 }
708}
709
710void* HAL_GetDMADirectPointer(HAL_DMAHandle handle) {
711 auto dma = dmaHandles->Get(handle);
712 return dma.get();
713}
714
715enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
716 HAL_DMASample* dmaSample,
Austin Schuh812d0d12021-11-04 20:16:48 -0700717 double timeoutSeconds,
Brian Silverman8fce7482020-01-05 13:18:21 -0800718 int32_t* remainingOut,
719 int32_t* status) {
720 DMA* dma = static_cast<DMA*>(dmaPointer);
721 *remainingOut = 0;
722 size_t remainingBytes = 0;
723
724 if (!dma->manager) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700725 *status = HAL_INVALID_DMA_STATE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800726 return HAL_DMA_ERROR;
727 }
728
729 dma->manager->read(dmaSample->readBuffer, dma->captureStore.captureSize,
Austin Schuh812d0d12021-11-04 20:16:48 -0700730 static_cast<uint32_t>(timeoutSeconds * 1000),
731 &remainingBytes, status);
Brian Silverman8fce7482020-01-05 13:18:21 -0800732
733 *remainingOut = remainingBytes / dma->captureStore.captureSize;
734
735 if (*status == 0) {
736 uint32_t lower_sample =
737 dmaSample->readBuffer[dma->captureStore.captureSize - 1];
738 dmaSample->timeStamp = HAL_ExpandFPGATime(lower_sample, status);
739 if (*status != 0) {
740 return HAL_DMA_ERROR;
741 }
742 dmaSample->triggerChannels = dma->captureStore.triggerChannels;
743 dmaSample->captureSize = dma->captureStore.captureSize;
744 std::memcpy(dmaSample->channelOffsets, dma->captureStore.channelOffsets,
745 sizeof(dmaSample->channelOffsets));
746 return HAL_DMA_OK;
747 } else if (*status == NiFpga_Status_FifoTimeout) {
748 *status = 0;
749 return HAL_DMA_TIMEOUT;
750 } else {
751 return HAL_DMA_ERROR;
752 }
753}
754
755enum HAL_DMAReadStatus HAL_ReadDMA(HAL_DMAHandle handle,
Austin Schuh812d0d12021-11-04 20:16:48 -0700756 HAL_DMASample* dmaSample,
757 double timeoutSeconds, int32_t* remainingOut,
758 int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800759 auto dma = dmaHandles->Get(handle);
760 if (!dma) {
761 *status = HAL_HANDLE_ERROR;
762 return HAL_DMA_ERROR;
763 }
764
Austin Schuh812d0d12021-11-04 20:16:48 -0700765 return HAL_ReadDMADirect(dma.get(), dmaSample, timeoutSeconds, remainingOut,
Brian Silverman8fce7482020-01-05 13:18:21 -0800766 status);
767}
768
769static uint32_t ReadDMAValue(const HAL_DMASample& dma, int valueType, int index,
770 int32_t* status) {
771 auto offset = dma.channelOffsets[valueType];
772 if (offset == -1) {
773 *status = NiFpga_Status_ResourceNotFound;
774 return 0;
775 }
776 return dma.readBuffer[offset + index];
777}
778
779uint64_t HAL_GetDMASampleTime(const HAL_DMASample* dmaSample, int32_t* status) {
780 return dmaSample->timeStamp;
781}
782
783int32_t HAL_GetDMASampleEncoderRaw(const HAL_DMASample* dmaSample,
784 HAL_EncoderHandle encoderHandle,
785 int32_t* status) {
786 HAL_FPGAEncoderHandle fpgaEncoderHandle = 0;
787 HAL_CounterHandle counterHandle = 0;
788 bool validEncoderHandle = hal::GetEncoderBaseHandle(
789 encoderHandle, &fpgaEncoderHandle, &counterHandle);
790
791 if (!validEncoderHandle) {
792 *status = HAL_HANDLE_ERROR;
793 return -1;
794 }
795
796 if (counterHandle != HAL_kInvalidHandle) {
797 return HAL_GetDMASampleCounter(dmaSample, counterHandle, status);
798 }
799
800 if (getHandleType(fpgaEncoderHandle) != HAL_HandleEnum::FPGAEncoder) {
801 *status = HAL_HANDLE_ERROR;
802 return -1;
803 }
804
805 int32_t index = getHandleIndex(fpgaEncoderHandle);
806 if (index < 0) {
807 *status = HAL_HANDLE_ERROR;
808 return -1;
809 }
810
811 uint32_t dmaWord = 0;
812 *status = 0;
813 if (index < 4) {
814 dmaWord = ReadDMAValue(*dmaSample, kEnable_Encoders_Low, index, status);
815 } else if (index < 8) {
816 dmaWord =
817 ReadDMAValue(*dmaSample, kEnable_Encoders_High, index - 4, status);
818 } else {
819 *status = NiFpga_Status_ResourceNotFound;
820 }
821 if (*status != 0) {
822 return -1;
823 }
824
825 return static_cast<int32_t>(dmaWord) >> 1;
826}
827
828int32_t HAL_GetDMASampleEncoderPeriodRaw(const HAL_DMASample* dmaSample,
829 HAL_EncoderHandle encoderHandle,
830 int32_t* status) {
831 HAL_FPGAEncoderHandle fpgaEncoderHandle = 0;
832 HAL_CounterHandle counterHandle = 0;
833 bool validEncoderHandle = hal::GetEncoderBaseHandle(
834 encoderHandle, &fpgaEncoderHandle, &counterHandle);
835
836 if (!validEncoderHandle) {
837 *status = HAL_HANDLE_ERROR;
838 return -1;
839 }
840
841 if (counterHandle != HAL_kInvalidHandle) {
842 return HAL_GetDMASampleCounterPeriod(dmaSample, counterHandle, status);
843 }
844
845 if (getHandleType(fpgaEncoderHandle) != HAL_HandleEnum::FPGAEncoder) {
846 *status = HAL_HANDLE_ERROR;
847 return -1;
848 }
849
850 int32_t index = getHandleIndex(fpgaEncoderHandle);
851 if (index < 0) {
852 *status = HAL_HANDLE_ERROR;
853 return -1;
854 }
855
856 uint32_t dmaWord = 0;
857 *status = 0;
858 if (index < 4) {
859 dmaWord =
860 ReadDMAValue(*dmaSample, kEnable_EncoderTimers_Low, index, status);
861 } else if (index < 8) {
862 dmaWord =
863 ReadDMAValue(*dmaSample, kEnable_EncoderTimers_High, index - 4, status);
864 } else {
865 *status = NiFpga_Status_ResourceNotFound;
866 }
867 if (*status != 0) {
868 return -1;
869 }
870
871 return static_cast<int32_t>(dmaWord) & 0x7FFFFF;
872}
873
874int32_t HAL_GetDMASampleCounter(const HAL_DMASample* dmaSample,
875 HAL_CounterHandle counterHandle,
876 int32_t* status) {
877 if (getHandleType(counterHandle) != HAL_HandleEnum::Counter) {
878 *status = HAL_HANDLE_ERROR;
879 return -1;
880 }
881
882 int32_t index = getHandleIndex(counterHandle);
883 if (index < 0) {
884 *status = HAL_HANDLE_ERROR;
885 return -1;
886 }
887
888 uint32_t dmaWord = 0;
889 *status = 0;
890 if (index < 4) {
891 dmaWord = ReadDMAValue(*dmaSample, kEnable_Counters_Low, index, status);
892 } else if (index < 8) {
893 dmaWord =
894 ReadDMAValue(*dmaSample, kEnable_Counters_High, index - 4, status);
895 } else {
896 *status = NiFpga_Status_ResourceNotFound;
897 }
898 if (*status != 0) {
899 return -1;
900 }
901
902 return static_cast<int32_t>(dmaWord) >> 1;
903}
904
905int32_t HAL_GetDMASampleCounterPeriod(const HAL_DMASample* dmaSample,
906 HAL_CounterHandle counterHandle,
907 int32_t* status) {
908 if (getHandleType(counterHandle) != HAL_HandleEnum::Counter) {
909 *status = HAL_HANDLE_ERROR;
910 return -1;
911 }
912
913 int32_t index = getHandleIndex(counterHandle);
914 if (index < 0) {
915 *status = HAL_HANDLE_ERROR;
916 return -1;
917 }
918
919 uint32_t dmaWord = 0;
920 *status = 0;
921 if (index < 4) {
922 dmaWord =
923 ReadDMAValue(*dmaSample, kEnable_CounterTimers_Low, index, status);
924 } else if (index < 8) {
925 dmaWord =
926 ReadDMAValue(*dmaSample, kEnable_CounterTimers_High, index - 4, status);
927 } else {
928 *status = NiFpga_Status_ResourceNotFound;
929 }
930 if (*status != 0) {
931 return -1;
932 }
933
934 return static_cast<int32_t>(dmaWord) & 0x7FFFFF;
935}
936
937HAL_Bool HAL_GetDMASampleDigitalSource(const HAL_DMASample* dmaSample,
938 HAL_Handle dSourceHandle,
939 int32_t* status) {
940 HAL_HandleEnum handleType = getHandleType(dSourceHandle);
941 int32_t index = getHandleIndex(dSourceHandle);
942
943 *status = 0;
944 if (handleType == HAL_HandleEnum::DIO) {
945 auto readVal = ReadDMAValue(*dmaSample, kEnable_DI, 0, status);
946 if (*status == 0) {
947 if (index < kNumDigitalHeaders) {
948 return (readVal >> index) & 0x1;
949 } else {
950 return (readVal >> (index + 6)) & 0x1;
951 }
952 }
953 } else if (handleType == HAL_HandleEnum::AnalogTrigger) {
954 auto readVal = ReadDMAValue(*dmaSample, kEnable_AnalogTriggers, 0, status);
955 if (*status == 0) {
956 return (readVal >> index) & 0x1;
957 }
958 } else {
959 *status = NiFpga_Status_InvalidParameter;
960 }
961 return false;
962}
963int32_t HAL_GetDMASampleAnalogInputRaw(const HAL_DMASample* dmaSample,
964 HAL_AnalogInputHandle aInHandle,
965 int32_t* status) {
966 if (getHandleType(aInHandle) != HAL_HandleEnum::AnalogInput) {
967 *status = HAL_HANDLE_ERROR;
968 return 0xFFFFFFFF;
969 }
970
971 int32_t index = getHandleIndex(aInHandle);
972 if (index < 0) {
973 *status = HAL_HANDLE_ERROR;
974 return 0xFFFFFFFF;
975 }
976
977 uint32_t dmaWord = 0;
978 if (index < 4) {
979 dmaWord = ReadDMAValue(*dmaSample, kEnable_AI0_Low, index / 2, status);
980 } else if (index < 8) {
981 dmaWord =
982 ReadDMAValue(*dmaSample, kEnable_AI0_High, (index - 4) / 2, status);
983 } else {
984 *status = NiFpga_Status_ResourceNotFound;
985 }
986 if (*status != 0) {
987 return 0xFFFFFFFF;
988 }
989
990 if (index % 2) {
991 return (dmaWord >> 16) & 0xffff;
992 } else {
993 return dmaWord & 0xffff;
994 }
995}
996
997int32_t HAL_GetDMASampleAveragedAnalogInputRaw(const HAL_DMASample* dmaSample,
998 HAL_AnalogInputHandle aInHandle,
999 int32_t* status) {
1000 if (getHandleType(aInHandle) != HAL_HandleEnum::AnalogInput) {
1001 *status = HAL_HANDLE_ERROR;
1002 return 0xFFFFFFFF;
1003 }
1004
1005 int32_t index = getHandleIndex(aInHandle);
1006 if (index < 0) {
1007 *status = HAL_HANDLE_ERROR;
1008 return 0xFFFFFFFF;
1009 }
1010
1011 uint32_t dmaWord = 0;
1012 if (index < 4) {
1013 dmaWord = ReadDMAValue(*dmaSample, kEnable_AIAveraged0_Low, index, status);
1014 } else if (index < 8) {
1015 dmaWord =
1016 ReadDMAValue(*dmaSample, kEnable_AIAveraged0_High, index - 4, status);
1017 } else {
1018 *status = NiFpga_Status_ResourceNotFound;
1019 }
1020 if (*status != 0) {
1021 return 0xFFFFFFFF;
1022 }
1023
1024 return dmaWord;
1025}
1026
1027void HAL_GetDMASampleAnalogAccumulator(const HAL_DMASample* dmaSample,
1028 HAL_AnalogInputHandle aInHandle,
1029 int64_t* count, int64_t* value,
1030 int32_t* status) {
1031 if (!HAL_IsAccumulatorChannel(aInHandle, status)) {
1032 *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
1033 return;
1034 }
1035
1036 int32_t index = getHandleIndex(aInHandle);
1037 if (index < 0) {
1038 *status = HAL_HANDLE_ERROR;
1039 return;
1040 }
1041
1042 uint32_t dmaWord = 0;
1043 uint32_t dmaValue1 = 0;
1044 uint32_t dmaValue2 = 0;
1045 if (index == 0) {
1046 dmaWord = ReadDMAValue(*dmaSample, kEnable_Accumulator0, index, status);
1047 dmaValue1 =
1048 ReadDMAValue(*dmaSample, kEnable_Accumulator0, index + 1, status);
1049 dmaValue2 =
1050 ReadDMAValue(*dmaSample, kEnable_Accumulator0, index + 2, status);
1051 } else if (index == 1) {
1052 dmaWord = ReadDMAValue(*dmaSample, kEnable_Accumulator1, index - 1, status);
1053 dmaValue1 = ReadDMAValue(*dmaSample, kEnable_Accumulator0, index, status);
1054 dmaValue2 =
1055 ReadDMAValue(*dmaSample, kEnable_Accumulator0, index + 1, status);
1056 } else {
1057 *status = NiFpga_Status_ResourceNotFound;
1058 }
1059 if (*status != 0) {
1060 return;
1061 }
1062
1063 *count = dmaWord;
1064
1065 *value = static_cast<int64_t>(dmaValue1) << 32 | dmaValue2;
1066}
1067
1068int32_t HAL_GetDMASampleDutyCycleOutputRaw(const HAL_DMASample* dmaSample,
1069 HAL_DutyCycleHandle dutyCycleHandle,
1070 int32_t* status) {
1071 if (getHandleType(dutyCycleHandle) != HAL_HandleEnum::DutyCycle) {
1072 *status = HAL_HANDLE_ERROR;
1073 return -1;
1074 }
1075
1076 int32_t index = getHandleIndex(dutyCycleHandle);
1077 if (index < 0) {
1078 *status = HAL_HANDLE_ERROR;
1079 return -1;
1080 }
1081
1082 uint32_t dmaWord = 0;
1083 *status = 0;
1084 if (index < 4) {
1085 dmaWord = ReadDMAValue(*dmaSample, kEnable_DutyCycle_Low, index, status);
1086 } else if (index < 8) {
1087 dmaWord =
1088 ReadDMAValue(*dmaSample, kEnable_DutyCycle_High, index - 4, status);
1089 } else {
1090 *status = NiFpga_Status_ResourceNotFound;
1091 }
1092 if (*status != 0) {
1093 return -1;
1094 }
1095 return dmaWord;
1096}
1097} // extern "C"