blob: 23e926424848c18e03b312e5e2b8d3e9776f07ba [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
James Kuszmaulcf324122023-01-14 14:07:17 -0800133 if (!dma) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700134 return;
James Kuszmaulcf324122023-01-14 14:07:17 -0800135 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800136
137 int32_t status = 0;
138 if (dma->manager) {
139 dma->manager->stop(&status);
140 }
141}
142
143void HAL_SetDMAPause(HAL_DMAHandle handle, HAL_Bool pause, int32_t* status) {
144 auto dma = dmaHandles->Get(handle);
145 if (!dma) {
146 *status = HAL_HANDLE_ERROR;
147 return;
148 }
149
Austin Schuh812d0d12021-11-04 20:16:48 -0700150 if (!dma->manager) {
151 *status = HAL_INVALID_DMA_STATE;
152 return;
153 }
154
Brian Silverman8fce7482020-01-05 13:18:21 -0800155 dma->aDMA->writeConfig_Pause(pause, status);
156}
Austin Schuh812d0d12021-11-04 20:16:48 -0700157
158void HAL_SetDMATimedTrigger(HAL_DMAHandle handle, double seconds,
159 int32_t* status) {
160 constexpr double baseMultipler = kSystemClockTicksPerMicrosecond * 1000000;
161 uint32_t cycles = static_cast<uint32_t>(baseMultipler * seconds);
162 HAL_SetDMATimedTriggerCycles(handle, cycles, status);
163}
164
165void HAL_SetDMATimedTriggerCycles(HAL_DMAHandle handle, uint32_t cycles,
166 int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800167 auto dma = dmaHandles->Get(handle);
168 if (!dma) {
169 *status = HAL_HANDLE_ERROR;
170 return;
171 }
172
Austin Schuh812d0d12021-11-04 20:16:48 -0700173 if (dma->manager) {
174 *status = HAL_INVALID_DMA_ADDITION;
175 return;
176 }
177
Brian Silverman8fce7482020-01-05 13:18:21 -0800178 if (cycles < 1) {
179 cycles = 1;
180 }
181
Austin Schuh812d0d12021-11-04 20:16:48 -0700182 dma->aDMA->writeConfig_ExternalClock(false, status);
183 if (*status != 0) {
184 return;
185 }
186
187 dma->aDMA->writeRate(cycles, status);
Brian Silverman8fce7482020-01-05 13:18:21 -0800188}
189
190void HAL_AddDMAEncoder(HAL_DMAHandle handle, HAL_EncoderHandle encoderHandle,
191 int32_t* status) {
192 // Detect a counter encoder vs an actual encoder, and use the right DMA calls
193 HAL_FPGAEncoderHandle fpgaEncoderHandle = HAL_kInvalidHandle;
194 HAL_CounterHandle counterHandle = HAL_kInvalidHandle;
195
196 bool validEncoderHandle = hal::GetEncoderBaseHandle(
197 encoderHandle, &fpgaEncoderHandle, &counterHandle);
198
199 if (!validEncoderHandle) {
200 *status = HAL_HANDLE_ERROR;
201 return;
202 }
203
204 if (counterHandle != HAL_kInvalidHandle) {
205 HAL_AddDMACounter(handle, counterHandle, status);
206 return;
207 }
208
209 auto dma = dmaHandles->Get(handle);
210 if (!dma) {
211 *status = HAL_HANDLE_ERROR;
212 return;
213 }
214
215 if (dma->manager) {
216 *status = HAL_INVALID_DMA_ADDITION;
217 return;
218 }
219
220 if (getHandleType(fpgaEncoderHandle) != HAL_HandleEnum::FPGAEncoder) {
221 *status = HAL_HANDLE_ERROR;
222 return;
223 }
224
225 int32_t index = getHandleIndex(fpgaEncoderHandle);
226 if (index < 0) {
227 *status = HAL_HANDLE_ERROR;
228 return;
229 }
230
231 if (index < 4) {
232 dma->aDMA->writeConfig_Enable_Encoders_Low(true, status);
233 } else if (index < 8) {
234 dma->aDMA->writeConfig_Enable_Encoders_High(true, status);
235 } else {
236 *status = NiFpga_Status_InvalidParameter;
237 }
238}
239
240void HAL_AddDMAEncoderPeriod(HAL_DMAHandle handle,
241 HAL_EncoderHandle encoderHandle, int32_t* status) {
242 // Detect a counter encoder vs an actual encoder, and use the right DMA calls
243 HAL_FPGAEncoderHandle fpgaEncoderHandle = HAL_kInvalidHandle;
244 HAL_CounterHandle counterHandle = HAL_kInvalidHandle;
245
246 bool validEncoderHandle = hal::GetEncoderBaseHandle(
247 encoderHandle, &fpgaEncoderHandle, &counterHandle);
248
249 if (!validEncoderHandle) {
250 *status = HAL_HANDLE_ERROR;
251 return;
252 }
253
254 if (counterHandle != HAL_kInvalidHandle) {
255 HAL_AddDMACounterPeriod(handle, counterHandle, status);
256 return;
257 }
258
259 auto dma = dmaHandles->Get(handle);
260 if (!dma) {
261 *status = HAL_HANDLE_ERROR;
262 return;
263 }
264
265 if (dma->manager) {
266 *status = HAL_INVALID_DMA_ADDITION;
267 return;
268 }
269
270 if (getHandleType(fpgaEncoderHandle) != HAL_HandleEnum::FPGAEncoder) {
271 *status = HAL_HANDLE_ERROR;
272 return;
273 }
274
275 int32_t index = getHandleIndex(fpgaEncoderHandle);
276 if (index < 0) {
277 *status = HAL_HANDLE_ERROR;
278 return;
279 }
280
281 if (index < 4) {
282 dma->aDMA->writeConfig_Enable_EncoderTimers_Low(true, status);
283 } else if (index < 8) {
284 dma->aDMA->writeConfig_Enable_EncoderTimers_High(true, status);
285 } else {
286 *status = NiFpga_Status_InvalidParameter;
287 }
288}
289
290void HAL_AddDMACounter(HAL_DMAHandle handle, HAL_CounterHandle counterHandle,
291 int32_t* status) {
292 auto dma = dmaHandles->Get(handle);
293 if (!dma) {
294 *status = HAL_HANDLE_ERROR;
295 return;
296 }
297
298 if (dma->manager) {
299 *status = HAL_INVALID_DMA_ADDITION;
300 return;
301 }
302
303 if (getHandleType(counterHandle) != HAL_HandleEnum::Counter) {
304 *status = HAL_HANDLE_ERROR;
305 return;
306 }
307
308 int32_t index = getHandleIndex(counterHandle);
309 if (index < 0) {
310 *status = HAL_HANDLE_ERROR;
311 return;
312 }
313
314 if (index < 4) {
315 dma->aDMA->writeConfig_Enable_Counters_Low(true, status);
316 } else if (index < 8) {
317 dma->aDMA->writeConfig_Enable_Counters_High(true, status);
318 } else {
319 *status = NiFpga_Status_InvalidParameter;
320 }
321}
322
323void HAL_AddDMACounterPeriod(HAL_DMAHandle handle,
324 HAL_CounterHandle counterHandle, int32_t* status) {
325 auto dma = dmaHandles->Get(handle);
326 if (!dma) {
327 *status = HAL_HANDLE_ERROR;
328 return;
329 }
330
331 if (dma->manager) {
332 *status = HAL_INVALID_DMA_ADDITION;
333 return;
334 }
335
336 if (getHandleType(counterHandle) != HAL_HandleEnum::Counter) {
337 *status = HAL_HANDLE_ERROR;
338 return;
339 }
340
341 int32_t index = getHandleIndex(counterHandle);
342 if (index < 0) {
343 *status = HAL_HANDLE_ERROR;
344 return;
345 }
346
347 if (index < 4) {
348 dma->aDMA->writeConfig_Enable_CounterTimers_Low(true, status);
349 } else if (index < 8) {
350 dma->aDMA->writeConfig_Enable_CounterTimers_High(true, status);
351 } else {
352 *status = NiFpga_Status_InvalidParameter;
353 }
354}
355
356void HAL_AddDMADigitalSource(HAL_DMAHandle handle,
357 HAL_Handle digitalSourceHandle, int32_t* status) {
358 auto dma = dmaHandles->Get(handle);
359 if (!dma) {
360 *status = HAL_HANDLE_ERROR;
361 return;
362 }
363
364 if (dma->manager) {
365 *status = HAL_INVALID_DMA_ADDITION;
366 return;
367 }
368
369 if (isHandleType(digitalSourceHandle, HAL_HandleEnum::AnalogTrigger)) {
370 dma->aDMA->writeConfig_Enable_AnalogTriggers(true, status);
371 } else if (isHandleType(digitalSourceHandle, HAL_HandleEnum::DIO)) {
372 dma->aDMA->writeConfig_Enable_DI(true, status);
373 } else {
374 *status = NiFpga_Status_InvalidParameter;
375 }
376}
377
378void HAL_AddDMAAnalogInput(HAL_DMAHandle handle,
379 HAL_AnalogInputHandle aInHandle, int32_t* status) {
380 auto dma = dmaHandles->Get(handle);
381 if (!dma) {
382 *status = HAL_HANDLE_ERROR;
383 return;
384 }
385
386 if (dma->manager) {
387 *status = HAL_INVALID_DMA_ADDITION;
388 return;
389 }
390
391 if (getHandleType(aInHandle) != HAL_HandleEnum::AnalogInput) {
392 *status = HAL_HANDLE_ERROR;
393 return;
394 }
395
396 int32_t index = getHandleIndex(aInHandle);
397 if (index < 0) {
398 *status = HAL_HANDLE_ERROR;
399 return;
400 }
401
402 if (index < 4) {
403 dma->aDMA->writeConfig_Enable_AI0_Low(true, status);
404 } else if (index < 8) {
405 dma->aDMA->writeConfig_Enable_AI0_High(true, status);
406 } else {
407 *status = NiFpga_Status_InvalidParameter;
408 }
409}
410
411void HAL_AddDMADutyCycle(HAL_DMAHandle handle,
412 HAL_DutyCycleHandle dutyCycleHandle, int32_t* status) {
413 auto dma = dmaHandles->Get(handle);
414 if (!dma) {
415 *status = HAL_HANDLE_ERROR;
416 return;
417 }
418
419 if (dma->manager) {
420 *status = HAL_INVALID_DMA_ADDITION;
421 return;
422 }
423
424 if (getHandleType(dutyCycleHandle) != HAL_HandleEnum::DutyCycle) {
425 *status = HAL_HANDLE_ERROR;
426 return;
427 }
428
429 int32_t index = getHandleIndex(dutyCycleHandle);
430 if (index < 0) {
431 *status = HAL_HANDLE_ERROR;
432 return;
433 }
434
435 if (index < 4) {
436 dma->aDMA->writeConfig_Enable_DutyCycle_Low(true, status);
437 } else if (index < 8) {
438 dma->aDMA->writeConfig_Enable_DutyCycle_High(true, status);
439 } else {
440 *status = NiFpga_Status_InvalidParameter;
441 }
442}
443
444void HAL_AddDMAAveragedAnalogInput(HAL_DMAHandle handle,
445 HAL_AnalogInputHandle aInHandle,
446 int32_t* status) {
447 auto dma = dmaHandles->Get(handle);
448 if (!dma) {
449 *status = HAL_HANDLE_ERROR;
450 return;
451 }
452
453 if (dma->manager) {
454 *status = HAL_INVALID_DMA_ADDITION;
455 return;
456 }
457
458 if (getHandleType(aInHandle) != HAL_HandleEnum::AnalogInput) {
459 *status = HAL_HANDLE_ERROR;
460 return;
461 }
462
463 int32_t index = getHandleIndex(aInHandle);
464 if (index < 0) {
465 *status = HAL_HANDLE_ERROR;
466 return;
467 }
468
469 if (index < 4) {
470 dma->aDMA->writeConfig_Enable_AIAveraged0_Low(true, status);
471 } else if (index < 8) {
472 dma->aDMA->writeConfig_Enable_AIAveraged0_High(true, status);
473 } else {
474 *status = NiFpga_Status_InvalidParameter;
475 }
476}
477
478void HAL_AddDMAAnalogAccumulator(HAL_DMAHandle handle,
479 HAL_AnalogInputHandle aInHandle,
480 int32_t* status) {
481 auto dma = dmaHandles->Get(handle);
482 if (!dma) {
483 *status = HAL_HANDLE_ERROR;
484 return;
485 }
486
487 if (dma->manager) {
488 *status = HAL_INVALID_DMA_ADDITION;
489 return;
490 }
491
492 if (!HAL_IsAccumulatorChannel(aInHandle, status)) {
493 *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
494 return;
495 }
496
497 int32_t index = getHandleIndex(aInHandle);
498 if (index < 0) {
499 *status = HAL_HANDLE_ERROR;
500 return;
501 }
502
503 if (index == 0) {
504 dma->aDMA->writeConfig_Enable_Accumulator0(true, status);
505 } else if (index == 1) {
506 dma->aDMA->writeConfig_Enable_Accumulator1(true, status);
507 } else {
508 *status = NiFpga_Status_InvalidParameter;
509 }
510}
511
Austin Schuh812d0d12021-11-04 20:16:48 -0700512int32_t HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
513 HAL_Handle digitalSourceHandle,
514 HAL_AnalogTriggerType analogTriggerType,
515 HAL_Bool rising, HAL_Bool falling,
516 int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800517 auto dma = dmaHandles->Get(handle);
518 if (!dma) {
519 *status = HAL_HANDLE_ERROR;
Austin Schuh812d0d12021-11-04 20:16:48 -0700520 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800521 }
522
523 if (dma->manager) {
524 *status = HAL_INVALID_DMA_ADDITION;
Austin Schuh812d0d12021-11-04 20:16:48 -0700525 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800526 }
527
528 int index = 0;
529 auto triggerChannels = dma->captureStore.triggerChannels;
530 do {
531 if (((triggerChannels >> index) & 0x1) == 0) {
532 break;
533 }
534 index++;
535 } while (index < 8);
536
537 if (index == 8) {
538 *status = NO_AVAILABLE_RESOURCES;
Austin Schuh812d0d12021-11-04 20:16:48 -0700539 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800540 }
541
542 dma->captureStore.triggerChannels |= (1 << index);
543
544 auto channelIndex = index;
545
Austin Schuh812d0d12021-11-04 20:16:48 -0700546 dma->aDMA->writeConfig_ExternalClock(true, status);
547 if (*status != 0) {
548 return 0;
549 }
550
551 dma->aDMA->writeRate(1, status);
552 if (*status != 0) {
553 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800554 }
555
556 uint8_t pin = 0;
557 uint8_t module = 0;
558 bool analogTrigger = false;
559 bool success = remapDigitalSource(digitalSourceHandle, analogTriggerType, pin,
560 module, analogTrigger);
561
562 if (!success) {
563 *status = PARAMETER_OUT_OF_RANGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700564 hal::SetLastError(status,
565 "Digital Source unabled to be mapped properly. Likely "
566 "invalid handle passed.");
567 return 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800568 }
569
570 tDMA::tExternalTriggers newTrigger;
571 newTrigger.FallingEdge = falling;
572 newTrigger.RisingEdge = rising;
573 newTrigger.ExternalClockSource_AnalogTrigger = analogTrigger;
574 newTrigger.ExternalClockSource_Channel = pin;
575 newTrigger.ExternalClockSource_Module = module;
576
577 dma->aDMA->writeExternalTriggers(channelIndex / 4, channelIndex % 4,
578 newTrigger, status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700579 return index;
580}
581
582void HAL_ClearDMASensors(HAL_DMAHandle handle, int32_t* status) {
583 auto dma = dmaHandles->Get(handle);
584 if (!dma) {
585 *status = HAL_HANDLE_ERROR;
586 return;
587 }
588
589 if (dma->manager) {
590 *status = HAL_INVALID_DMA_STATE;
591 return;
592 }
593
594 bool existingExternal = dma->aDMA->readConfig_ExternalClock(status);
595 if (*status != 0) {
596 return;
597 }
598
599 tDMA::tConfig config;
600 std::memset(&config, 0, sizeof(config));
601 config.Pause = true;
602 config.ExternalClock = existingExternal;
603 dma->aDMA->writeConfig(config, status);
604}
605
606void HAL_ClearDMAExternalTriggers(HAL_DMAHandle handle, int32_t* status) {
607 auto dma = dmaHandles->Get(handle);
608 if (!dma) {
609 *status = HAL_HANDLE_ERROR;
610 return;
611 }
612
613 if (dma->manager) {
614 *status = HAL_INVALID_DMA_STATE;
615 return;
616 }
617
618 dma->captureStore.triggerChannels = 0;
619 tDMA::tExternalTriggers newTrigger;
620 std::memset(&newTrigger, 0, sizeof(newTrigger));
621 for (unsigned char reg = 0; reg < tDMA::kNumExternalTriggersRegisters;
622 reg++) {
623 for (unsigned char bit = 0; bit < tDMA::kNumExternalTriggersElements;
624 bit++) {
625 dma->aDMA->writeExternalTriggers(reg, bit, newTrigger, status);
626 }
627 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800628}
629
630void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status) {
631 auto dma = dmaHandles->Get(handle);
632 if (!dma) {
633 *status = HAL_HANDLE_ERROR;
634 return;
635 }
636
637 if (dma->manager) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700638 *status = HAL_INVALID_DMA_STATE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800639 return;
640 }
641
642 tDMA::tConfig config = dma->aDMA->readConfig(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700643 if (*status != 0) {
644 return;
645 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800646
647 {
648 size_t accum_size = 0;
649#define SET_SIZE(bit) \
650 if (config.bit) { \
651 dma->captureStore.channelOffsets[k##bit] = accum_size; \
652 accum_size += kChannelSize[k##bit]; \
653 } else { \
654 dma->captureStore.channelOffsets[k##bit] = -1; \
655 }
656 SET_SIZE(Enable_AI0_Low);
657 SET_SIZE(Enable_AI0_High);
658 SET_SIZE(Enable_AIAveraged0_Low);
659 SET_SIZE(Enable_AIAveraged0_High);
660 SET_SIZE(Enable_AI1_Low);
661 SET_SIZE(Enable_AI1_High);
662 SET_SIZE(Enable_AIAveraged1_Low);
663 SET_SIZE(Enable_AIAveraged1_High);
664 SET_SIZE(Enable_Accumulator0);
665 SET_SIZE(Enable_Accumulator1);
666 SET_SIZE(Enable_DI);
667 SET_SIZE(Enable_AnalogTriggers);
668 SET_SIZE(Enable_Counters_Low);
669 SET_SIZE(Enable_Counters_High);
670 SET_SIZE(Enable_CounterTimers_Low);
671 SET_SIZE(Enable_CounterTimers_High);
672 SET_SIZE(Enable_Encoders_Low);
673 SET_SIZE(Enable_Encoders_High);
674 SET_SIZE(Enable_EncoderTimers_Low);
675 SET_SIZE(Enable_EncoderTimers_High);
676 SET_SIZE(Enable_DutyCycle_Low);
677 SET_SIZE(Enable_DutyCycle_High);
678#undef SET_SIZE
679 dma->captureStore.captureSize = accum_size + 1;
680 }
681
Austin Schuh812d0d12021-11-04 20:16:48 -0700682 uint32_t byteDepth = queueDepth * dma->captureStore.captureSize;
683
684 dma->manager = std::make_unique<tDMAManager>(g_DMA_index, byteDepth, status);
Brian Silverman8fce7482020-01-05 13:18:21 -0800685 if (*status != 0) {
686 return;
687 }
688
Austin Schuh812d0d12021-11-04 20:16:48 -0700689 dma->aDMA->writeConfig_Pause(false, status);
690
Brian Silverman8fce7482020-01-05 13:18:21 -0800691 dma->manager->start(status);
692 dma->manager->stop(status);
693 dma->manager->start(status);
694}
695
696void HAL_StopDMA(HAL_DMAHandle handle, int32_t* status) {
697 auto dma = dmaHandles->Get(handle);
698 if (!dma) {
699 *status = HAL_HANDLE_ERROR;
700 return;
701 }
702
703 if (dma->manager) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700704 dma->aDMA->writeConfig_Pause(true, status);
705 *status = 0;
Brian Silverman8fce7482020-01-05 13:18:21 -0800706 dma->manager->stop(status);
707 dma->manager = nullptr;
708 }
709}
710
711void* HAL_GetDMADirectPointer(HAL_DMAHandle handle) {
712 auto dma = dmaHandles->Get(handle);
James Kuszmaulcf324122023-01-14 14:07:17 -0800713 if (dma == nullptr) {
714 return nullptr;
715 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800716 return dma.get();
717}
718
719enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
720 HAL_DMASample* dmaSample,
Austin Schuh812d0d12021-11-04 20:16:48 -0700721 double timeoutSeconds,
Brian Silverman8fce7482020-01-05 13:18:21 -0800722 int32_t* remainingOut,
723 int32_t* status) {
724 DMA* dma = static_cast<DMA*>(dmaPointer);
725 *remainingOut = 0;
726 size_t remainingBytes = 0;
727
728 if (!dma->manager) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700729 *status = HAL_INVALID_DMA_STATE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800730 return HAL_DMA_ERROR;
731 }
732
733 dma->manager->read(dmaSample->readBuffer, dma->captureStore.captureSize,
Austin Schuh812d0d12021-11-04 20:16:48 -0700734 static_cast<uint32_t>(timeoutSeconds * 1000),
735 &remainingBytes, status);
Brian Silverman8fce7482020-01-05 13:18:21 -0800736
737 *remainingOut = remainingBytes / dma->captureStore.captureSize;
738
739 if (*status == 0) {
740 uint32_t lower_sample =
741 dmaSample->readBuffer[dma->captureStore.captureSize - 1];
742 dmaSample->timeStamp = HAL_ExpandFPGATime(lower_sample, status);
743 if (*status != 0) {
744 return HAL_DMA_ERROR;
745 }
746 dmaSample->triggerChannels = dma->captureStore.triggerChannels;
747 dmaSample->captureSize = dma->captureStore.captureSize;
748 std::memcpy(dmaSample->channelOffsets, dma->captureStore.channelOffsets,
749 sizeof(dmaSample->channelOffsets));
750 return HAL_DMA_OK;
751 } else if (*status == NiFpga_Status_FifoTimeout) {
752 *status = 0;
753 return HAL_DMA_TIMEOUT;
754 } else {
755 return HAL_DMA_ERROR;
756 }
757}
758
759enum HAL_DMAReadStatus HAL_ReadDMA(HAL_DMAHandle handle,
Austin Schuh812d0d12021-11-04 20:16:48 -0700760 HAL_DMASample* dmaSample,
761 double timeoutSeconds, int32_t* remainingOut,
762 int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800763 auto dma = dmaHandles->Get(handle);
764 if (!dma) {
765 *status = HAL_HANDLE_ERROR;
766 return HAL_DMA_ERROR;
767 }
768
Austin Schuh812d0d12021-11-04 20:16:48 -0700769 return HAL_ReadDMADirect(dma.get(), dmaSample, timeoutSeconds, remainingOut,
Brian Silverman8fce7482020-01-05 13:18:21 -0800770 status);
771}
772
773static uint32_t ReadDMAValue(const HAL_DMASample& dma, int valueType, int index,
774 int32_t* status) {
775 auto offset = dma.channelOffsets[valueType];
776 if (offset == -1) {
777 *status = NiFpga_Status_ResourceNotFound;
778 return 0;
779 }
780 return dma.readBuffer[offset + index];
781}
782
783uint64_t HAL_GetDMASampleTime(const HAL_DMASample* dmaSample, int32_t* status) {
784 return dmaSample->timeStamp;
785}
786
787int32_t HAL_GetDMASampleEncoderRaw(const HAL_DMASample* dmaSample,
788 HAL_EncoderHandle encoderHandle,
789 int32_t* status) {
790 HAL_FPGAEncoderHandle fpgaEncoderHandle = 0;
791 HAL_CounterHandle counterHandle = 0;
792 bool validEncoderHandle = hal::GetEncoderBaseHandle(
793 encoderHandle, &fpgaEncoderHandle, &counterHandle);
794
795 if (!validEncoderHandle) {
796 *status = HAL_HANDLE_ERROR;
797 return -1;
798 }
799
800 if (counterHandle != HAL_kInvalidHandle) {
801 return HAL_GetDMASampleCounter(dmaSample, counterHandle, status);
802 }
803
804 if (getHandleType(fpgaEncoderHandle) != HAL_HandleEnum::FPGAEncoder) {
805 *status = HAL_HANDLE_ERROR;
806 return -1;
807 }
808
809 int32_t index = getHandleIndex(fpgaEncoderHandle);
810 if (index < 0) {
811 *status = HAL_HANDLE_ERROR;
812 return -1;
813 }
814
815 uint32_t dmaWord = 0;
816 *status = 0;
817 if (index < 4) {
818 dmaWord = ReadDMAValue(*dmaSample, kEnable_Encoders_Low, index, status);
819 } else if (index < 8) {
820 dmaWord =
821 ReadDMAValue(*dmaSample, kEnable_Encoders_High, index - 4, status);
822 } else {
823 *status = NiFpga_Status_ResourceNotFound;
824 }
825 if (*status != 0) {
826 return -1;
827 }
828
829 return static_cast<int32_t>(dmaWord) >> 1;
830}
831
832int32_t HAL_GetDMASampleEncoderPeriodRaw(const HAL_DMASample* dmaSample,
833 HAL_EncoderHandle encoderHandle,
834 int32_t* status) {
835 HAL_FPGAEncoderHandle fpgaEncoderHandle = 0;
836 HAL_CounterHandle counterHandle = 0;
837 bool validEncoderHandle = hal::GetEncoderBaseHandle(
838 encoderHandle, &fpgaEncoderHandle, &counterHandle);
839
840 if (!validEncoderHandle) {
841 *status = HAL_HANDLE_ERROR;
842 return -1;
843 }
844
845 if (counterHandle != HAL_kInvalidHandle) {
846 return HAL_GetDMASampleCounterPeriod(dmaSample, counterHandle, status);
847 }
848
849 if (getHandleType(fpgaEncoderHandle) != HAL_HandleEnum::FPGAEncoder) {
850 *status = HAL_HANDLE_ERROR;
851 return -1;
852 }
853
854 int32_t index = getHandleIndex(fpgaEncoderHandle);
855 if (index < 0) {
856 *status = HAL_HANDLE_ERROR;
857 return -1;
858 }
859
860 uint32_t dmaWord = 0;
861 *status = 0;
862 if (index < 4) {
863 dmaWord =
864 ReadDMAValue(*dmaSample, kEnable_EncoderTimers_Low, index, status);
865 } else if (index < 8) {
866 dmaWord =
867 ReadDMAValue(*dmaSample, kEnable_EncoderTimers_High, index - 4, status);
868 } else {
869 *status = NiFpga_Status_ResourceNotFound;
870 }
871 if (*status != 0) {
872 return -1;
873 }
874
875 return static_cast<int32_t>(dmaWord) & 0x7FFFFF;
876}
877
878int32_t HAL_GetDMASampleCounter(const HAL_DMASample* dmaSample,
879 HAL_CounterHandle counterHandle,
880 int32_t* status) {
881 if (getHandleType(counterHandle) != HAL_HandleEnum::Counter) {
882 *status = HAL_HANDLE_ERROR;
883 return -1;
884 }
885
886 int32_t index = getHandleIndex(counterHandle);
887 if (index < 0) {
888 *status = HAL_HANDLE_ERROR;
889 return -1;
890 }
891
892 uint32_t dmaWord = 0;
893 *status = 0;
894 if (index < 4) {
895 dmaWord = ReadDMAValue(*dmaSample, kEnable_Counters_Low, index, status);
896 } else if (index < 8) {
897 dmaWord =
898 ReadDMAValue(*dmaSample, kEnable_Counters_High, index - 4, status);
899 } else {
900 *status = NiFpga_Status_ResourceNotFound;
901 }
902 if (*status != 0) {
903 return -1;
904 }
905
906 return static_cast<int32_t>(dmaWord) >> 1;
907}
908
909int32_t HAL_GetDMASampleCounterPeriod(const HAL_DMASample* dmaSample,
910 HAL_CounterHandle counterHandle,
911 int32_t* status) {
912 if (getHandleType(counterHandle) != HAL_HandleEnum::Counter) {
913 *status = HAL_HANDLE_ERROR;
914 return -1;
915 }
916
917 int32_t index = getHandleIndex(counterHandle);
918 if (index < 0) {
919 *status = HAL_HANDLE_ERROR;
920 return -1;
921 }
922
923 uint32_t dmaWord = 0;
924 *status = 0;
925 if (index < 4) {
926 dmaWord =
927 ReadDMAValue(*dmaSample, kEnable_CounterTimers_Low, index, status);
928 } else if (index < 8) {
929 dmaWord =
930 ReadDMAValue(*dmaSample, kEnable_CounterTimers_High, index - 4, status);
931 } else {
932 *status = NiFpga_Status_ResourceNotFound;
933 }
934 if (*status != 0) {
935 return -1;
936 }
937
938 return static_cast<int32_t>(dmaWord) & 0x7FFFFF;
939}
940
941HAL_Bool HAL_GetDMASampleDigitalSource(const HAL_DMASample* dmaSample,
942 HAL_Handle dSourceHandle,
943 int32_t* status) {
944 HAL_HandleEnum handleType = getHandleType(dSourceHandle);
945 int32_t index = getHandleIndex(dSourceHandle);
946
947 *status = 0;
948 if (handleType == HAL_HandleEnum::DIO) {
949 auto readVal = ReadDMAValue(*dmaSample, kEnable_DI, 0, status);
950 if (*status == 0) {
951 if (index < kNumDigitalHeaders) {
952 return (readVal >> index) & 0x1;
953 } else {
954 return (readVal >> (index + 6)) & 0x1;
955 }
956 }
957 } else if (handleType == HAL_HandleEnum::AnalogTrigger) {
958 auto readVal = ReadDMAValue(*dmaSample, kEnable_AnalogTriggers, 0, status);
959 if (*status == 0) {
960 return (readVal >> index) & 0x1;
961 }
962 } else {
963 *status = NiFpga_Status_InvalidParameter;
964 }
965 return false;
966}
967int32_t HAL_GetDMASampleAnalogInputRaw(const HAL_DMASample* dmaSample,
968 HAL_AnalogInputHandle aInHandle,
969 int32_t* status) {
970 if (getHandleType(aInHandle) != HAL_HandleEnum::AnalogInput) {
971 *status = HAL_HANDLE_ERROR;
972 return 0xFFFFFFFF;
973 }
974
975 int32_t index = getHandleIndex(aInHandle);
976 if (index < 0) {
977 *status = HAL_HANDLE_ERROR;
978 return 0xFFFFFFFF;
979 }
980
981 uint32_t dmaWord = 0;
982 if (index < 4) {
983 dmaWord = ReadDMAValue(*dmaSample, kEnable_AI0_Low, index / 2, status);
984 } else if (index < 8) {
985 dmaWord =
986 ReadDMAValue(*dmaSample, kEnable_AI0_High, (index - 4) / 2, status);
987 } else {
988 *status = NiFpga_Status_ResourceNotFound;
989 }
990 if (*status != 0) {
991 return 0xFFFFFFFF;
992 }
993
994 if (index % 2) {
995 return (dmaWord >> 16) & 0xffff;
996 } else {
997 return dmaWord & 0xffff;
998 }
999}
1000
1001int32_t HAL_GetDMASampleAveragedAnalogInputRaw(const HAL_DMASample* dmaSample,
1002 HAL_AnalogInputHandle aInHandle,
1003 int32_t* status) {
1004 if (getHandleType(aInHandle) != HAL_HandleEnum::AnalogInput) {
1005 *status = HAL_HANDLE_ERROR;
1006 return 0xFFFFFFFF;
1007 }
1008
1009 int32_t index = getHandleIndex(aInHandle);
1010 if (index < 0) {
1011 *status = HAL_HANDLE_ERROR;
1012 return 0xFFFFFFFF;
1013 }
1014
1015 uint32_t dmaWord = 0;
1016 if (index < 4) {
1017 dmaWord = ReadDMAValue(*dmaSample, kEnable_AIAveraged0_Low, index, status);
1018 } else if (index < 8) {
1019 dmaWord =
1020 ReadDMAValue(*dmaSample, kEnable_AIAveraged0_High, index - 4, status);
1021 } else {
1022 *status = NiFpga_Status_ResourceNotFound;
1023 }
1024 if (*status != 0) {
1025 return 0xFFFFFFFF;
1026 }
1027
1028 return dmaWord;
1029}
1030
1031void HAL_GetDMASampleAnalogAccumulator(const HAL_DMASample* dmaSample,
1032 HAL_AnalogInputHandle aInHandle,
1033 int64_t* count, int64_t* value,
1034 int32_t* status) {
1035 if (!HAL_IsAccumulatorChannel(aInHandle, status)) {
1036 *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
1037 return;
1038 }
1039
1040 int32_t index = getHandleIndex(aInHandle);
1041 if (index < 0) {
1042 *status = HAL_HANDLE_ERROR;
1043 return;
1044 }
1045
1046 uint32_t dmaWord = 0;
1047 uint32_t dmaValue1 = 0;
1048 uint32_t dmaValue2 = 0;
1049 if (index == 0) {
1050 dmaWord = ReadDMAValue(*dmaSample, kEnable_Accumulator0, index, status);
1051 dmaValue1 =
1052 ReadDMAValue(*dmaSample, kEnable_Accumulator0, index + 1, status);
1053 dmaValue2 =
1054 ReadDMAValue(*dmaSample, kEnable_Accumulator0, index + 2, status);
1055 } else if (index == 1) {
1056 dmaWord = ReadDMAValue(*dmaSample, kEnable_Accumulator1, index - 1, status);
1057 dmaValue1 = ReadDMAValue(*dmaSample, kEnable_Accumulator0, index, status);
1058 dmaValue2 =
1059 ReadDMAValue(*dmaSample, kEnable_Accumulator0, index + 1, status);
1060 } else {
1061 *status = NiFpga_Status_ResourceNotFound;
1062 }
1063 if (*status != 0) {
1064 return;
1065 }
1066
1067 *count = dmaWord;
1068
1069 *value = static_cast<int64_t>(dmaValue1) << 32 | dmaValue2;
1070}
1071
1072int32_t HAL_GetDMASampleDutyCycleOutputRaw(const HAL_DMASample* dmaSample,
1073 HAL_DutyCycleHandle dutyCycleHandle,
1074 int32_t* status) {
1075 if (getHandleType(dutyCycleHandle) != HAL_HandleEnum::DutyCycle) {
1076 *status = HAL_HANDLE_ERROR;
1077 return -1;
1078 }
1079
1080 int32_t index = getHandleIndex(dutyCycleHandle);
1081 if (index < 0) {
1082 *status = HAL_HANDLE_ERROR;
1083 return -1;
1084 }
1085
1086 uint32_t dmaWord = 0;
1087 *status = 0;
1088 if (index < 4) {
1089 dmaWord = ReadDMAValue(*dmaSample, kEnable_DutyCycle_Low, index, status);
1090 } else if (index < 8) {
1091 dmaWord =
1092 ReadDMAValue(*dmaSample, kEnable_DutyCycle_High, index - 4, status);
1093 } else {
1094 *status = NiFpga_Status_ResourceNotFound;
1095 }
1096 if (*status != 0) {
1097 return -1;
1098 }
1099 return dmaWord;
1100}
1101} // extern "C"