1 //
2 // Copyright 2013-2014 Ettus Research LLC
3 // Copyright 2018 Ettus Research, a National Instruments Company
4 //
5 // SPDX-License-Identifier: GPL-3.0-or-later
6 //
7 
8 #include <uhd/transport/nirio/niriok_proxy_impl_v1.h>
9 #include <cstring>
10 
11 // "push" and "pop" introduced in GCC 4.6; works with all clang
12 #if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 5)
13 #    pragma GCC diagnostic push
14 #endif
15 #if defined(__clang__) || defined(__GNUC__)
16 #    pragma GCC diagnostic ignored "-Wmissing-field-initializers"
17 #endif
18 
19 // CTL_CODE macro for non-win OSes
20 #ifndef UHD_PLATFORM_WIN32
21 #    define CTL_CODE(a, controlCode, b, c) (controlCode)
22 #endif
23 
24 const uint32_t NIRIO_IOCTL_BASE = 0x800;
25 
26 const uint32_t NIRIO_IOCTL_SYNCOP = CTL_CODE(FILE_DEVICE_UNKNOWN,
27     NIRIO_IOCTL_BASE + 4,
28     METHOD_OUT_DIRECT,
29     FILE_READ_DATA | FILE_WRITE_DATA);
30 ///< The synchronous operation code. Note: We
31 /// must use METHOD_OUT_DIRECT on the syncOp()
32 /// IOCTL to ensure the contents of the output
33 /// block are available in the kernel.
34 
35 const uint32_t NIRIO_IOCTL_GET_IFACE_NUM = CTL_CODE(FILE_DEVICE_UNKNOWN,
36     NIRIO_IOCTL_BASE + 6,
37     METHOD_BUFFERED,
38     FILE_READ_DATA); ///< Get the interface number for a device
39 
40 // const uint32_t NIRIO_IOCTL_GET_SESSION =
41 // CTL_CODE(FILE_DEVICE_UNKNOWN,
42 // NIRIO_IOCTL_BASE + 8,
43 // METHOD_BUFFERED,
44 // FILE_READ_ACCESS);  ///< Gets a previously opened session to a device
45 
46 const uint32_t NIRIO_IOCTL_POST_OPEN = CTL_CODE(FILE_DEVICE_UNKNOWN,
47     NIRIO_IOCTL_BASE + 9,
48     METHOD_BUFFERED,
49     FILE_READ_ACCESS); ///< Called after opening a session
50 
51 const uint32_t NIRIO_IOCTL_PRE_CLOSE = CTL_CODE(FILE_DEVICE_UNKNOWN,
52     NIRIO_IOCTL_BASE + 10,
53     METHOD_BUFFERED,
54     FILE_READ_ACCESS); ///< Called before closing a session
55 
56 namespace uhd { namespace niusrprio {
57 // -------------------------------
58 // Function Codes: defined as integers rather than enums because they
59 // are going to be carried accross boundaries so size matters
60 
61 struct NIRIO_FUNC
62 {
63     static const uint32_t GET32             = 0x00000001;
64     static const uint32_t SET32             = 0x00000002;
65     static const uint32_t SET_DRIVER_CONFIG = 0x00000007;
66     static const uint32_t FIFO              = 0x00000008;
67     static const uint32_t IO                = 0x0000000A;
68     static const uint32_t FIFO_STOP_ALL     = 0x0000000C;
69     static const uint32_t ADD_RESOURCE      = 0x0000000D;
70     static const uint32_t GET_STRING        = 0x0000000E;
71     static const uint32_t SET_STRING        = 0x0000000F;
72     static const uint32_t DOWNLOAD          = 0x00000013;
73     static const uint32_t RESET             = 0x00000014;
74 };
75 
76 struct NIRIO_RESOURCE
77 {
78     static const uint32_t INPUT_FIFO  = 0xD0000001;
79     static const uint32_t OUTPUT_FIFO = 0xD0000002;
80 };
81 
82 struct NIRIO_FIFO
83 {
84     static const uint32_t CONFIGURE = 0x80000001;
85     static const uint32_t START     = 0x80000002;
86     static const uint32_t STOP      = 0x80000003;
87     static const uint32_t READ      = 0x80000004;
88     static const uint32_t WRITE     = 0x80000005;
89     static const uint32_t WAIT      = 0x80000006;
90     static const uint32_t GRANT     = 0x80000007;
91 };
92 
93 struct NIRIO_IO
94 {
95     static const uint32_t POKE64             = 0xA0000005;
96     static const uint32_t POKE32             = 0xA0000006;
97     static const uint32_t POKE16             = 0xA0000007;
98     static const uint32_t POKE8              = 0xA0000008;
99     static const uint32_t PEEK64             = 0xA0000009;
100     static const uint32_t PEEK32             = 0xA000000A;
101     static const uint32_t PEEK16             = 0xA000000B;
102     static const uint32_t PEEK8              = 0xA000000C;
103     static const uint32_t READ_BLOCK         = 0xA000000D;
104     static const uint32_t WRITE_BLOCK        = 0xA000000E;
105     static const uint32_t GET_IO_WINDOW      = 0xA000000F;
106     static const uint32_t GET_IO_WINDOW_SIZE = 0xA0000010;
107 };
108 
109 struct nirio_ioctl_packet_t
110 {
nirio_ioctl_packet_tuhd::niusrprio::nirio_ioctl_packet_t111     nirio_ioctl_packet_t(
112         void* const _outBuf, const uint32_t _outSize, const int32_t _statusCode)
113     {
114         outBuf._64BitField = 0;
115         outBuf.pointer     = _outBuf;
116         outSize            = _outSize;
117         statusCode         = _statusCode;
118     };
119 
120     union {
121         void* pointer;
122         uint64_t _64BitField;
123     } outBuf;
124 
125     uint32_t outSize;
126     int32_t statusCode;
127 };
128 
129 struct nirio_syncop_in_params_t
130 {
131     uint32_t function;
132     uint32_t subfunction;
133 
134     union {
135         struct
136         {
137             uint32_t attribute;
138             uint32_t value;
139         } attribute32;
140 
141         struct
142         {
143             uint32_t attribute;
144             uint64_t value;
145         } attribute64;
146 
147         struct
148         {
149             uint32_t attribute;
150         } attributeStr;
151 
152         struct
153         {
154             uint32_t attribute;
155         } download;
156 
157         union {
158             struct
159             {
160                 uint32_t reserved_field_0_0_0;
161             } reserved_field_0_0;
162             struct
163             {
164                 uint32_t reserved_field_0_1_0;
165                 uint32_t reserved_field_0_1_1;
166             } reserved_field_0_1;
167             struct
168             {
169                 uint32_t reserved_field_0_2_0;
170             } reserved_field_0_2;
171         } reserved_field_0;
172 
173         union {
174             struct
175             {
176                 uint32_t channel;
177                 uint32_t baseAddress;
178                 uint32_t depthInSamples;
179                 uint32_t version;
180             } fifo;
181             struct
182             {
183                 uint32_t channel;
184                 uint32_t baseAddress;
185                 uint32_t depthInSamples;
186                 uint32_t version;
187                 uint32_t scalarType;
188                 uint32_t bitWidth;
189             } fifoWithDataType;
190             struct
191             {
192                 uint64_t rangeBaseAddress;
193                 uint32_t rangeSizeInBytes;
194                 uint32_t rangeAttribute;
195             } atomic; // obsolete
196         } add;
197 
198         struct
199         {
200             uint32_t channel;
201 
202             union {
203                 struct
204                 {
205                     uint32_t requestedDepth;
206                     uint8_t requiresActuals;
207                 } config;
208                 struct
209                 {
210                     uint32_t timeout;
211                 } read;
212                 struct
213                 {
214                     uint32_t timeout;
215                     uint32_t scalarType;
216                     uint32_t bitWidth;
217                 } readWithDataType;
218                 struct
219                 {
220                     uint32_t timeout;
221                 } write;
222                 struct
223                 {
224                     uint32_t timeout;
225                     uint32_t scalarType;
226                     uint32_t bitWidth;
227                 } writeWithDataType;
228                 struct
229                 {
230                     uint32_t elementsRequested;
231                     uint32_t scalarType;
232                     uint32_t bitWidth;
233                     uint32_t timeout;
234                     uint8_t output;
235                 } wait;
236                 struct
237                 {
238                     uint32_t elements;
239                 } grant;
240             } op;
241         } fifo;
242 
243         struct
244         {
245             uint64_t reserved_field_1_0;
246             uint32_t reserved_field_1_1;
247             uint32_t reserved_field_1_2;
248         } reserved_field_1; // Obsolete
249 
250         struct
251         {
252             uint32_t offset;
253             union {
254                 uint64_t value64;
255                 uint32_t value32;
256                 uint16_t value16;
257                 uint8_t value8;
258             } value;
259             union {
260                 uint32_t sizeToMap;
261             } memoryMappedIoWindow;
262         } io;
263 
264         struct
265         {
266             uint32_t reserved_field_2_0;
267             uint32_t reserved_field_2_1;
268         } reserved_field_2;
269 
270         struct
271         {
272             uint32_t reserved_field_3_0;
273         } reserved_field_3;
274 
275         union {
276             struct
277             {
278                 uint32_t reserved_field_4_0;
279                 int32_t reserved_field_4_1;
280             } wait;
281         } reserved_field_4;
282 
283     } params;
284 
285     uint32_t inbufByteLen;
286 
287     union {
288         const void* pointer;
289         uint64_t _64BitField;
290     } inbuf;
291 };
292 
init_syncop_in_params(nirio_syncop_in_params_t & param,const void * const buf,const uint32_t len)293 static inline void init_syncop_in_params(
294     nirio_syncop_in_params_t& param, const void* const buf, const uint32_t len)
295 {
296     param.inbuf._64BitField = 0;
297     param.inbuf.pointer     = buf;
298     param.inbufByteLen      = len;
299 }
300 
301 struct nirio_syncop_out_params_t
302 {
303     union {
304         struct
305         {
306             uint32_t value;
307         } attribute32;
308 
309         struct
310         {
311             uint64_t value;
312         } attribute64;
313 
314         union {
315             struct
316             {
317                 uint32_t reserved_field_0_0;
318             } enable;
319         } reserved_field_0;
320 
321         struct
322         {
323             union {
324                 struct
325                 {
326                     uint32_t actualDepth;
327                     uint32_t actualSize;
328                 } config;
329                 struct
330                 {
331                     uint32_t numberRead;
332                     uint32_t numberRemaining;
333                 } read;
334                 struct
335                 {
336                     uint32_t numberRemaining;
337                 } write;
338                 struct
339                 {
340                     union {
341                         void* pointer;
342                         uint64_t _64BitField;
343                     } elements;
344                 } wait;
345             } op;
346         } fifo;
347 
348         struct
349         {
350             union {
351                 union {
352                     uint64_t value64;
353                     uint32_t value32;
354                     uint16_t value16;
355                     uint8_t value8;
356                 } value;
357                 union {
358                     void* memoryMappedAddress;
359                     uint64_t _64BitField;
360                 } memoryMappedIoWindow;
361                 union {
362                     uint32_t size;
363                 } memoryMappedIoWindowSize;
364             };
365         } io;
366 
367         uint32_t stringLength;
368 
369         struct
370         {
371             uint32_t reserved_field_1_0;
372         } reserved_field_1;
373 
374     } params;
375 
376     uint32_t outbufByteLen;
377 
378     union {
379         void* pointer;
380         uint64_t _64BitField;
381     } outbuf;
382 };
383 
init_syncop_out_params(nirio_syncop_out_params_t & param,void * buf,uint32_t len)384 static inline void init_syncop_out_params(
385     nirio_syncop_out_params_t& param, void* buf, uint32_t len)
386 {
387     param.outbuf._64BitField = 0;
388     param.outbuf.pointer     = buf;
389     param.outbufByteLen      = len;
390 }
391 
392 //-------------------------------------------------------
393 // niriok_proxy_impl_v1
394 //-------------------------------------------------------
niriok_proxy_impl_v1()395 niriok_proxy_impl_v1::niriok_proxy_impl_v1() {}
396 
~niriok_proxy_impl_v1()397 niriok_proxy_impl_v1::~niriok_proxy_impl_v1()
398 {
399     close();
400 }
401 
open(const std::string & interface_path)402 nirio_status niriok_proxy_impl_v1::open(const std::string& interface_path)
403 {
404     WRITER_LOCK
405 
406     if (interface_path.empty())
407         return NiRio_Status_ResourceNotFound;
408 
409     // close if already open.
410     // use non-locking _close since we already have the lock
411     _close();
412 
413     nirio_status status = NiRio_Status_Success;
414     nirio_status_chain(
415         nirio_driver_iface::rio_open(interface_path, _device_handle), status);
416     if (nirio_status_not_fatal(status)) {
417         nirio_status_chain(nirio_driver_iface::rio_ioctl(
418                                _device_handle, NIRIO_IOCTL_POST_OPEN, NULL, 0, NULL, 0),
419             status);
420         nirio_ioctl_packet_t out(&_interface_num, sizeof(_interface_num), 0);
421         nirio_status_chain(
422             nirio_driver_iface::rio_ioctl(
423                 _device_handle, NIRIO_IOCTL_GET_IFACE_NUM, NULL, 0, &out, sizeof(out)),
424             status);
425 
426         if (nirio_status_fatal(status))
427             _close();
428     }
429     return status;
430 }
431 
close(void)432 void niriok_proxy_impl_v1::close(void)
433 {
434     WRITER_LOCK
435 
436     _close();
437 }
438 
439 // this protected _close doesn't acquire the lock, so it can be used in methods
440 // that already have the lock
_close()441 void niriok_proxy_impl_v1::_close()
442 {
443     if (nirio_driver_iface::rio_isopen(_device_handle)) {
444         nirio_driver_iface::rio_ioctl(
445             _device_handle, NIRIO_IOCTL_PRE_CLOSE, NULL, 0, NULL, 0);
446         nirio_driver_iface::rio_close(_device_handle);
447     }
448 }
449 
reset()450 nirio_status niriok_proxy_impl_v1::reset()
451 {
452     READER_LOCK
453 
454     nirio_syncop_in_params_t in   = {};
455     nirio_syncop_out_params_t out = {};
456 
457     in.function = NIRIO_FUNC::RESET;
458 
459     return sync_operation(&in, sizeof(in), &out, sizeof(out));
460 }
461 
get_version(nirio_version_t type,uint32_t & major,uint32_t & upgrade,uint32_t & maintenance,char & phase,uint32_t & build)462 nirio_status niriok_proxy_impl_v1::get_version(nirio_version_t type,
463     uint32_t& major,
464     uint32_t& upgrade,
465     uint32_t& maintenance,
466     char& phase,
467     uint32_t& build)
468 {
469     nirio_device_attribute32_t version_attr =
470         (type == CURRENT) ? RIO_CURRENT_VERSION : RIO_OLDEST_COMPATIBLE_VERSION;
471     uint32_t raw_version = 0;
472     nirio_status status  = get_attribute(version_attr, raw_version);
473 
474     major       = (raw_version & VERSION_MAJOR_MASK) >> VERSION_MAJOR_SHIFT;
475     upgrade     = (raw_version & VERSION_UPGRD_MASK) >> VERSION_UPGRD_SHIFT;
476     maintenance = (raw_version & VERSION_MAINT_MASK) >> VERSION_MAINT_SHIFT;
477     build       = (raw_version & VERSION_BUILD_MASK) >> VERSION_BUILD_SHIFT;
478 
479     uint32_t phase_num = (raw_version & VERSION_PHASE_MASK) >> VERSION_PHASE_SHIFT;
480     switch (phase_num) {
481         case 0:
482             phase = 'd';
483             break;
484         case 1:
485             phase = 'a';
486             break;
487         case 2:
488             phase = 'b';
489             break;
490         case 3:
491             phase = 'f';
492             break;
493     }
494 
495     return status;
496 }
497 
sync_operation(const void * writeBuffer,size_t writeBufferLength,void * readBuffer,size_t readBufferLength)498 nirio_status niriok_proxy_impl_v1::sync_operation(const void* writeBuffer,
499     size_t writeBufferLength,
500     void* readBuffer,
501     size_t readBufferLength)
502 {
503     READER_LOCK
504 
505     nirio_ioctl_packet_t out(readBuffer, readBufferLength, 0);
506     nirio_status ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
507         NIRIO_IOCTL_SYNCOP,
508         writeBuffer,
509         writeBufferLength,
510         &out,
511         sizeof(out));
512     if (nirio_status_fatal(ioctl_status))
513         return ioctl_status;
514 
515     return out.statusCode;
516 }
517 
get_attribute(const nirio_device_attribute32_t attribute,uint32_t & attrValue)518 nirio_status niriok_proxy_impl_v1::get_attribute(
519     const nirio_device_attribute32_t attribute, uint32_t& attrValue)
520 {
521     nirio_syncop_in_params_t in   = {};
522     nirio_syncop_out_params_t out = {};
523 
524     in.function                     = NIRIO_FUNC::GET32;
525     in.params.attribute32.attribute = static_cast<uint32_t>(attribute);
526 
527     nirio_status status = sync_operation(&in, sizeof(in), &out, sizeof(out));
528 
529     attrValue = out.params.attribute32.value;
530     return status;
531 }
532 
set_attribute(const nirio_device_attribute32_t attribute,const uint32_t value)533 nirio_status niriok_proxy_impl_v1::set_attribute(
534     const nirio_device_attribute32_t attribute, const uint32_t value)
535 {
536     nirio_syncop_in_params_t in   = {};
537     nirio_syncop_out_params_t out = {};
538 
539     in.function                     = NIRIO_FUNC::SET32;
540     in.params.attribute32.attribute = static_cast<uint32_t>(attribute);
541     in.params.attribute32.value     = value;
542 
543     return sync_operation(&in, sizeof(in), &out, sizeof(out));
544 }
545 
peek(uint32_t offset,uint32_t & value)546 nirio_status niriok_proxy_impl_v1::peek(uint32_t offset, uint32_t& value)
547 {
548     if (offset % 4 != 0)
549         return NiRio_Status_MisalignedAccess;
550 
551     nirio_syncop_in_params_t in   = {};
552     nirio_syncop_out_params_t out = {};
553 
554     in.function         = NIRIO_FUNC::IO;
555     in.subfunction      = NIRIO_IO::PEEK32;
556     in.params.io.offset = offset;
557 
558     nirio_status status = sync_operation(&in, sizeof(in), &out, sizeof(out));
559     value               = out.params.io.value.value32;
560     return status;
561 }
562 
peek(uint32_t offset,uint64_t & value)563 nirio_status niriok_proxy_impl_v1::peek(uint32_t offset, uint64_t& value)
564 {
565     if (offset % 8 != 0)
566         return NiRio_Status_MisalignedAccess;
567 
568     nirio_syncop_in_params_t in   = {};
569     nirio_syncop_out_params_t out = {};
570 
571     in.function         = NIRIO_FUNC::IO;
572     in.subfunction      = NIRIO_IO::PEEK64;
573     in.params.io.offset = offset;
574 
575     nirio_status status = sync_operation(&in, sizeof(in), &out, sizeof(out));
576     value               = out.params.io.value.value64;
577     return status;
578 }
579 
poke(uint32_t offset,const uint32_t & value)580 nirio_status niriok_proxy_impl_v1::poke(uint32_t offset, const uint32_t& value)
581 {
582     if (offset % 4 != 0)
583         return NiRio_Status_MisalignedAccess;
584 
585     nirio_syncop_in_params_t in   = {};
586     nirio_syncop_out_params_t out = {};
587 
588     in.function                = NIRIO_FUNC::IO;
589     in.subfunction             = NIRIO_IO::POKE32;
590     in.params.io.offset        = offset;
591     in.params.io.value.value32 = value;
592 
593     return sync_operation(&in, sizeof(in), &out, sizeof(out));
594 }
595 
poke(uint32_t offset,const uint64_t & value)596 nirio_status niriok_proxy_impl_v1::poke(uint32_t offset, const uint64_t& value)
597 {
598     if (offset % 8 != 0)
599         return NiRio_Status_MisalignedAccess;
600 
601     nirio_syncop_in_params_t in   = {};
602     nirio_syncop_out_params_t out = {};
603 
604     in.function                = NIRIO_FUNC::IO;
605     in.subfunction             = NIRIO_IO::POKE64;
606     in.params.io.offset        = offset;
607     in.params.io.value.value64 = value;
608 
609     return sync_operation(&in, sizeof(in), &out, sizeof(out));
610 }
611 
map_fifo_memory(uint32_t fifo_instance,size_t size,nirio_driver_iface::rio_mmap_t & map)612 nirio_status niriok_proxy_impl_v1::map_fifo_memory(
613     uint32_t fifo_instance, size_t size, nirio_driver_iface::rio_mmap_t& map)
614 {
615     READER_LOCK
616 
617     return nirio_driver_iface::rio_mmap(
618         _device_handle, GET_FIFO_MEMORY_TYPE(fifo_instance), size, true, map);
619 }
620 
unmap_fifo_memory(nirio_driver_iface::rio_mmap_t & map)621 nirio_status niriok_proxy_impl_v1::unmap_fifo_memory(nirio_driver_iface::rio_mmap_t& map)
622 {
623     READER_LOCK
624 
625     return nirio_driver_iface::rio_munmap(map);
626 }
627 
stop_all_fifos()628 nirio_status niriok_proxy_impl_v1::stop_all_fifos()
629 {
630     nirio_syncop_in_params_t in   = {};
631     nirio_syncop_out_params_t out = {};
632 
633     in.function = NIRIO_FUNC::FIFO_STOP_ALL;
634 
635     return sync_operation(&in, sizeof(in), &out, sizeof(out));
636 }
637 
add_fifo_resource(const nirio_fifo_info_t & fifo_info)638 nirio_status niriok_proxy_impl_v1::add_fifo_resource(const nirio_fifo_info_t& fifo_info)
639 {
640     nirio_syncop_in_params_t in   = {};
641     nirio_syncop_out_params_t out = {};
642 
643     in.function = NIRIO_FUNC::ADD_RESOURCE;
644     if (fifo_info.direction == OUTPUT_FIFO)
645         in.subfunction = NIRIO_RESOURCE::OUTPUT_FIFO;
646     else
647         in.subfunction = NIRIO_RESOURCE::INPUT_FIFO;
648 
649     in.params.add.fifoWithDataType.channel        = fifo_info.channel;
650     in.params.add.fifoWithDataType.baseAddress    = fifo_info.base_addr;
651     in.params.add.fifoWithDataType.depthInSamples = fifo_info.depth;
652     in.params.add.fifoWithDataType.scalarType =
653         static_cast<uint32_t>(fifo_info.scalar_type);
654     in.params.add.fifoWithDataType.bitWidth = fifo_info.bitWidth;
655     in.params.add.fifoWithDataType.version  = fifo_info.version;
656     // fifo_info.integerWordLength is not needed by the v1 kernel interface
657 
658     return sync_operation(&in, sizeof(in), &out, sizeof(out));
659 }
660 
set_device_config()661 nirio_status niriok_proxy_impl_v1::set_device_config()
662 {
663     nirio_syncop_in_params_t in   = {};
664     nirio_syncop_out_params_t out = {};
665 
666     in.function    = NIRIO_FUNC::SET_DRIVER_CONFIG;
667     in.subfunction = 0;
668 
669     return sync_operation(&in, sizeof(in), &out, sizeof(out));
670 }
671 
start_fifo(uint32_t channel)672 nirio_status niriok_proxy_impl_v1::start_fifo(uint32_t channel)
673 {
674     nirio_syncop_in_params_t in   = {};
675     nirio_syncop_out_params_t out = {};
676 
677     in.function    = NIRIO_FUNC::FIFO;
678     in.subfunction = NIRIO_FIFO::START;
679 
680     in.params.fifo.channel = channel;
681 
682     return sync_operation(&in, sizeof(in), &out, sizeof(out));
683 }
684 
stop_fifo(uint32_t channel)685 nirio_status niriok_proxy_impl_v1::stop_fifo(uint32_t channel)
686 {
687     nirio_syncop_in_params_t in   = {};
688     nirio_syncop_out_params_t out = {};
689 
690     in.function    = NIRIO_FUNC::FIFO;
691     in.subfunction = NIRIO_FIFO::STOP;
692 
693     in.params.fifo.channel = channel;
694 
695     return sync_operation(&in, sizeof(in), &out, sizeof(out));
696 }
697 
configure_fifo(uint32_t channel,uint32_t requested_depth,uint8_t requires_actuals,uint32_t & actual_depth,uint32_t & actual_size)698 nirio_status niriok_proxy_impl_v1::configure_fifo(uint32_t channel,
699     uint32_t requested_depth,
700     uint8_t requires_actuals,
701     uint32_t& actual_depth,
702     uint32_t& actual_size)
703 {
704     nirio_status status = NiRio_Status_Success;
705 
706     nirio_syncop_in_params_t in   = {};
707     nirio_syncop_out_params_t out = {};
708 
709     in.function    = NIRIO_FUNC::FIFO;
710     in.subfunction = NIRIO_FIFO::CONFIGURE;
711 
712     in.params.fifo.channel                   = channel;
713     in.params.fifo.op.config.requestedDepth  = requested_depth;
714     in.params.fifo.op.config.requiresActuals = requires_actuals;
715 
716     status = sync_operation(&in, sizeof(in), &out, sizeof(out));
717     if (nirio_status_fatal(status))
718         return status;
719 
720     actual_depth = out.params.fifo.op.config.actualDepth;
721     actual_size  = out.params.fifo.op.config.actualSize;
722 
723     return status;
724 }
725 
wait_on_fifo(uint32_t channel,uint32_t elements_requested,uint32_t scalar_type,uint32_t bit_width,uint32_t timeout,uint8_t output,void * & data_pointer,uint32_t & elements_acquired,uint32_t & elements_remaining)726 nirio_status niriok_proxy_impl_v1::wait_on_fifo(uint32_t channel,
727     uint32_t elements_requested,
728     uint32_t scalar_type,
729     uint32_t bit_width,
730     uint32_t timeout,
731     uint8_t output,
732     void*& data_pointer,
733     uint32_t& elements_acquired,
734     uint32_t& elements_remaining)
735 {
736     nirio_status status = NiRio_Status_Success;
737 
738     nirio_syncop_in_params_t in = {};
739     uint32_t stuffed[2];
740     nirio_syncop_out_params_t out = {};
741     init_syncop_out_params(out, stuffed, sizeof(stuffed));
742 
743     in.function    = NIRIO_FUNC::FIFO;
744     in.subfunction = NIRIO_FIFO::WAIT;
745 
746     in.params.fifo.channel                   = channel;
747     in.params.fifo.op.wait.elementsRequested = elements_requested;
748     in.params.fifo.op.wait.scalarType        = scalar_type;
749     in.params.fifo.op.wait.bitWidth          = bit_width;
750     in.params.fifo.op.wait.output            = output;
751     in.params.fifo.op.wait.timeout           = timeout;
752 
753     status = sync_operation(&in, sizeof(in), &out, sizeof(out));
754     if (nirio_status_fatal(status))
755         return status;
756 
757     data_pointer       = out.params.fifo.op.wait.elements.pointer;
758     elements_acquired  = stuffed[0];
759     elements_remaining = stuffed[1];
760 
761     return status;
762 }
763 
grant_fifo(uint32_t channel,uint32_t elements_to_grant)764 nirio_status niriok_proxy_impl_v1::grant_fifo(
765     uint32_t channel, uint32_t elements_to_grant)
766 {
767     nirio_syncop_in_params_t in   = {};
768     nirio_syncop_out_params_t out = {};
769 
770     in.function    = NIRIO_FUNC::FIFO;
771     in.subfunction = NIRIO_FIFO::GRANT;
772 
773     in.params.fifo.channel           = channel;
774     in.params.fifo.op.grant.elements = elements_to_grant;
775 
776     return sync_operation(&in, sizeof(in), &out, sizeof(out));
777 }
778 
read_fifo(uint32_t channel,uint32_t elements_to_read,void * buffer,uint32_t buffer_datatype_width,uint32_t scalar_type,uint32_t bit_width,uint32_t timeout,uint32_t & number_read,uint32_t & number_remaining)779 nirio_status niriok_proxy_impl_v1::read_fifo(uint32_t channel,
780     uint32_t elements_to_read,
781     void* buffer,
782     uint32_t buffer_datatype_width,
783     uint32_t scalar_type,
784     uint32_t bit_width,
785     uint32_t timeout,
786     uint32_t& number_read,
787     uint32_t& number_remaining)
788 {
789     nirio_status status = NiRio_Status_Success;
790 
791     nirio_syncop_in_params_t in   = {};
792     nirio_syncop_out_params_t out = {};
793     init_syncop_out_params(out, buffer, elements_to_read * buffer_datatype_width);
794 
795     in.function    = NIRIO_FUNC::FIFO;
796     in.subfunction = NIRIO_FIFO::READ;
797 
798     in.params.fifo.channel                        = channel;
799     in.params.fifo.op.readWithDataType.timeout    = timeout;
800     in.params.fifo.op.readWithDataType.scalarType = scalar_type;
801     in.params.fifo.op.readWithDataType.bitWidth   = bit_width;
802 
803     status = sync_operation(&in, sizeof(in), &out, sizeof(out));
804     if (nirio_status_fatal(status) && (status != NiRio_Status_FifoTimeout))
805         return status;
806 
807     number_read      = out.params.fifo.op.read.numberRead;
808     number_remaining = out.params.fifo.op.read.numberRemaining;
809 
810     return status;
811 }
812 
write_fifo(uint32_t channel,uint32_t elements_to_write,void * buffer,uint32_t buffer_datatype_width,uint32_t scalar_type,uint32_t bit_width,uint32_t timeout,uint32_t & number_remaining)813 nirio_status niriok_proxy_impl_v1::write_fifo(uint32_t channel,
814     uint32_t elements_to_write,
815     void* buffer,
816     uint32_t buffer_datatype_width,
817     uint32_t scalar_type,
818     uint32_t bit_width,
819     uint32_t timeout,
820     uint32_t& number_remaining)
821 {
822     nirio_status status = NiRio_Status_Success;
823 
824     nirio_syncop_in_params_t in = {};
825     init_syncop_in_params(in, buffer, elements_to_write * buffer_datatype_width);
826     nirio_syncop_out_params_t out = {};
827 
828     in.function    = NIRIO_FUNC::FIFO;
829     in.subfunction = NIRIO_FIFO::WRITE;
830 
831     in.params.fifo.channel                         = channel;
832     in.params.fifo.op.writeWithDataType.timeout    = timeout;
833     in.params.fifo.op.writeWithDataType.scalarType = scalar_type;
834     in.params.fifo.op.writeWithDataType.bitWidth   = bit_width;
835 
836     status = sync_operation(&in, sizeof(in), &out, sizeof(out));
837     if (nirio_status_fatal(status) && (status != NiRio_Status_FifoTimeout))
838         return status;
839 
840     number_remaining = out.params.fifo.op.write.numberRemaining;
841 
842     return status;
843 }
844 
845 }} // namespace uhd::niusrprio
846 
847 #if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 5)
848 #    pragma GCC diagnostic pop
849 #endif
850