Skip to content

Commit c24880e

Browse files
mgumblestrainmike
authored andcommitted
Adding Fifo Configuration support and adding new status's (#14)
* Support for Advanced FIFO Configurations with RIO 17.6 * Added quering the FPGA VI State with RIO 18.0
1 parent dbc9f42 commit c24880e

File tree

3 files changed

+266
-1
lines changed

3 files changed

+266
-1
lines changed

nifpga/nifpga.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,95 @@ def _return_ctype(self):
4848
return _datatype_ctype[self]
4949

5050

51+
class FifoPropertyType(Enum):
52+
""" Types of FIFO Properties, intended to abstract away the C Type. """
53+
I32 = 1
54+
U32 = 2
55+
I64 = 3
56+
U64 = 4
57+
Ptr = 5
58+
59+
def __str__(self):
60+
return self.name
61+
62+
def _return_ctype(self):
63+
""" Returns the associated ctype of a given property type. """
64+
_propertyType_ctype = {
65+
FifoPropertyType.I32: ctypes.c_int32,
66+
FifoPropertyType.U32: ctypes.c_uint32,
67+
FifoPropertyType.I64: ctypes.c_int64,
68+
FifoPropertyType.U64: ctypes.c_uint64,
69+
FifoPropertyType.Ptr: ctypes.c_void_p
70+
}
71+
return _propertyType_ctype[self]
72+
73+
74+
class FifoProperty(Enum):
75+
BytesPerElement = 1 # U32
76+
BufferAllocationGranularityElements = 2 # U32
77+
BufferSizeElements = 3 # U64
78+
MirroredElements = 4 # U64
79+
DmaBufferType = 5 # I32
80+
DmaBuffer = 6 # Ptr
81+
FlowControl = 7 # I32
82+
83+
def __str__(self):
84+
return self.name
85+
86+
87+
class FlowControl(Enum):
88+
""" When flow control is disabled, the FIFO no longer acts like a FIFO.
89+
The FIFO will overwrite data in this mode. The FPGA fully controls when
90+
data transfers. This can be useful when regenerating a waveform or when
91+
you only care about the most recent data.
92+
For Host to Target FIFOs, this only disables flow control when the entire FIFO
93+
has been written once.
94+
For Target to Host FIFOs, flow control is disabled on start and the FPGA can
95+
begin writing then.
96+
"""
97+
DisableFlowControl = 1
98+
""" Default FIFO behavior. No data is lost, data only moves when there is
99+
room for it.
100+
"""
101+
EnableFlowControl = 2
102+
103+
104+
class DmaBufferType(Enum):
105+
""" Allocated by RIO means the driver take the other properties and create
106+
a buffer that meets their requirements.
107+
"""
108+
AllocatedByRIO = 1
109+
""" Allocated by User means you will allocate a buffer and set the DMA Buffer
110+
property with your buffer. The driver will then use this buffer as the
111+
underlying host memory in the FIFO.
112+
"""
113+
AllocatedByUser = 2
114+
115+
116+
_fifo_properties_to_types = {
117+
FifoProperty.BytesPerElement: FifoPropertyType.U32,
118+
FifoProperty.BufferAllocationGranularityElements: FifoPropertyType.U32,
119+
FifoProperty.BufferSizeElements: FifoPropertyType.U64,
120+
FifoProperty.MirroredElements: FifoPropertyType.U64,
121+
FifoProperty.DmaBufferType: FifoPropertyType.I32,
122+
FifoProperty.DmaBuffer: FifoPropertyType.Ptr,
123+
FifoProperty.FlowControl: FifoPropertyType.I32,
124+
}
125+
126+
127+
class FpgaViState(Enum):
128+
""" The FPGA VI has either been downloaded and not run, or the VI was aborted
129+
or reset. """
130+
NotRunning = 0
131+
""" An error has occurred. """
132+
Invalid = 1
133+
""" The FPGA VI is currently executing. """
134+
Running = 2
135+
""" The FPGA VI stopped normally. This indicates it was not aborted or reset,
136+
but instead reached the end of any loops it was executing and ended. """
137+
NaturallyStopped = 3
138+
139+
51140
_SessionType = ctypes.c_uint32
52141
_IrqContextType = ctypes.c_void_p
53142

@@ -244,6 +333,38 @@ def __init__(self):
244333
NamedArgtype("inBufferSize", ctypes.c_size_t),
245334
NamedArgtype("outBuffer", ctypes.c_void_p),
246335
NamedArgtype("outBufferSize", ctypes.c_size_t),
336+
]),
337+
LibraryFunctionInfo(
338+
pretty_name="FindRegisterPrivate",
339+
name_in_library="NiFpgaDll_FindRegisterPrivate",
340+
named_argtypes=[
341+
NamedArgtype("session", _SessionType),
342+
NamedArgtype("name", ctypes.c_char_p),
343+
NamedArgtype("expectedType", ctypes.c_uint32),
344+
NamedArgtype("offset", ctypes.POINTER(ctypes.c_uint32)),
345+
]),
346+
LibraryFunctionInfo(
347+
pretty_name="FindFifoPrivate",
348+
name_in_library="NiFpgaDll_FindFifoPrivate",
349+
named_argtypes=[
350+
NamedArgtype("session", _SessionType),
351+
NamedArgtype("name", ctypes.c_char_p),
352+
NamedArgtype("expectedType", ctypes.c_uint32),
353+
NamedArgtype("fifoNumber", ctypes.POINTER(ctypes.c_uint32)),
354+
]),
355+
LibraryFunctionInfo(
356+
pretty_name="GetFpgaViState",
357+
name_in_library="NiFpgaDll_GetFpgaViState",
358+
named_argtypes=[
359+
NamedArgtype("session", _SessionType),
360+
NamedArgtype("state", ctypes.POINTER(ctypes.c_uint32)),
361+
]),
362+
LibraryFunctionInfo(
363+
pretty_name="CommitFifoConfiguration",
364+
name_in_library="NiFpgaDll_CommitFifoConfiguration",
365+
named_argtypes=[
366+
NamedArgtype("session", _SessionType),
367+
NamedArgtype("fifo", ctypes.c_uint32),
247368
])
248369
] # list of function_infos
249370

@@ -331,6 +452,29 @@ def __init__(self):
331452
NamedArgtype("elements remaining", ctypes.POINTER(ctypes.c_size_t)),
332453
]),
333454
]) # end of library_function_infos.extend() call
455+
456+
for fifoPropertyType in FifoPropertyType:
457+
type_ctype = fifoPropertyType._return_ctype()
458+
library_function_infos.extend([
459+
LibraryFunctionInfo(
460+
pretty_name="GetFifoProperty%s" % fifoPropertyType,
461+
name_in_library="NiFpgaDll_GetFifoProperty%s" % fifoPropertyType,
462+
named_argtypes=[
463+
NamedArgtype("session", _SessionType),
464+
NamedArgtype("fifo", ctypes.c_uint32),
465+
NamedArgtype("property", ctypes.c_uint32),
466+
NamedArgtype("value", ctypes.POINTER(type_ctype)),
467+
]),
468+
LibraryFunctionInfo(
469+
pretty_name="SetFifoProperty%s" % fifoPropertyType,
470+
name_in_library="NiFpgaDll_SetFifoProperty%s" % fifoPropertyType,
471+
named_argtypes=[
472+
NamedArgtype("session", _SessionType),
473+
NamedArgtype("fifo", ctypes.c_uint32),
474+
NamedArgtype("property", ctypes.c_uint32),
475+
NamedArgtype("value", type_ctype),
476+
]),
477+
])
334478
try:
335479
super(_NiFpga, self).__init__(library_name="NiFpga",
336480
library_function_infos=library_function_infos)

nifpga/session.py

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
from .nifpga import (_SessionType, _IrqContextType, _NiFpga, DataType,
88
OPEN_ATTRIBUTE_NO_RUN, RUN_ATTRIBUTE_WAIT_UNTIL_DONE,
9-
CLOSE_ATTRIBUTE_NO_RESET_IF_LAST_SESSION)
9+
CLOSE_ATTRIBUTE_NO_RESET_IF_LAST_SESSION, FifoProperty,
10+
_fifo_properties_to_types, FlowControl, DmaBufferType,
11+
FpgaViState)
1012
from .bitfile import Bitfile
1113
from .status import InvalidSessionError
1214
from collections import namedtuple
@@ -28,6 +30,7 @@ class Session(object):
2830
2931
with Session(bitfile="myBitfilePath.lvbitx", resource="RIO0") as session:
3032
session.run()
33+
FpgaAlreadyRunningWarning: pass
3134
session.download()
3235
session.abort()
3336
session.reset()
@@ -177,6 +180,13 @@ def reset(self):
177180
""" Resets the FPGA VI. """
178181
self._nifpga.Reset(self._session)
179182

183+
@property
184+
def fpga_vi_state(self):
185+
""" Returns the current state of the FPGA VI. """
186+
state = ctypes.c_uint32()
187+
self._nifpga.GetFpgaViState(self._session, state)
188+
return FpgaViState(state.value)
189+
180190
def _irq_ordinals_to_bitmask(self, ordinals):
181191
bitmask = 0
182192
for ordinal in ordinals:
@@ -580,6 +590,10 @@ def get_peer_to_peer_endpoint(self):
580590
self._nifpga.GetPeerToPeerFifoEndpoint(self._session, self._number, endpoint)
581591
return endpoint.value
582592

593+
def commit_configuration(self):
594+
""" Resolves and Commits property changes made to the FIFO. """
595+
self._nifpga.CommitFifoConfiguration(self._session, self._number)
596+
583597
@property
584598
def name(self):
585599
""" Property of a Fifo that contains its name. """
@@ -589,3 +603,97 @@ def name(self):
589603
def datatype(self):
590604
""" Property of a Fifo that contains its datatype. """
591605
return self._datatype
606+
607+
def _get_fifo_property(self, prop):
608+
prop_type = _fifo_properties_to_types[prop]
609+
value = (prop_type._return_ctype())(0)
610+
value_pointer = ctypes.pointer(value)
611+
self._nifpga['GetFifoProperty%s' % prop_type](self._session, self._number, prop.value, value_pointer)
612+
return value.value
613+
614+
def _set_fifo_property(self, prop, value):
615+
prop_type = _fifo_properties_to_types[prop]
616+
self._nifpga['SetFifoProperty%s' % prop_type](self._session, self._number, prop.value, value)
617+
618+
@property
619+
def buffer_allocation_granularity(self):
620+
""" The allocation granularity of the host memory part of a DMA FIFO.
621+
622+
By default this will usually be a page size, which is optimal for most
623+
devices. This property can be used to customize it.
624+
"""
625+
return self._get_fifo_property(FifoProperty.BufferAllocationGranularityElements)
626+
627+
@buffer_allocation_granularity.setter
628+
def buffer_allocation_granularity(self, value):
629+
self._set_fifo_property(FifoProperty.BufferAllocationGranularityElements, value)
630+
631+
@property
632+
def buffer_size(self):
633+
""" The size in elements of the Host Memory part of a DMA FIFO. """
634+
return self._get_fifo_property(FifoProperty.BufferSizeElements)
635+
636+
@buffer_size.setter
637+
def buffer_size(self, value):
638+
self._set_fifo_property(FifoProperty.BufferSizeElements, value)
639+
640+
@property
641+
def _mirror_size(self):
642+
""" The amount of elements in the Host Memory part of the DMA FIFO that
643+
mirror elements at the beginning.
644+
645+
The Host Memory part of a DMA FIFO is a circular buffer. This means that
646+
when we hit the end of the buffer we have to deal with the logic of wrapping
647+
around the buffer. Mirrored elements are elements at the beginning of
648+
the buffer that are mapped twice in memory to the end of the buffer.
649+
Settings this value can allow us to avoid wrap arounds.
650+
651+
This is mostly useful when using our Zero Copy API. Its not yet
652+
supported in Python though, so this property is private.
653+
"""
654+
return self._get_fifo_property(FifoProperty.MirroredElements)
655+
656+
@_mirror_size.setter
657+
def _mirror_size(self, value):
658+
self._set_fifo_property(FifoProperty.MirroredElements, value)
659+
660+
@property
661+
def _dma_buffer_type(self):
662+
return self._get_fifo_property(FifoProperty.DmaBufferType)
663+
664+
@_dma_buffer_type.setter
665+
def _dma_buffer_type(self, value):
666+
if not isinstance(value, DmaBufferType):
667+
raise TypeError("_dma_buffer_type must be set to a nifpga.DmaBufferType")
668+
self._set_fifo_property(FifoProperty.DmaBufferType, value.value)
669+
670+
@property
671+
def _dma_buffer(self):
672+
return self._get_fifo_property(FifoProperty.DmaBuffer)
673+
674+
@_dma_buffer.setter
675+
def _dma_buffer(self, value):
676+
self._set_fifo_property(FifoProperty.DmaBuffer, value)
677+
678+
@property
679+
def flow_control(self):
680+
""" Controls whether the FPGA will wait for the host when using FIFOs.
681+
682+
If flow control is disabled, the FPGA will have free reign to read or
683+
write elements before the host is ready. This means the FIFO no longer
684+
acts in a First In First Out manner.
685+
686+
For Host To Target FIFOs, this feature is useful when you want to put
687+
something like a waveform in a FIFO and let the FPGA continue reading
688+
that waveform over and over without any involvement from the host.
689+
690+
For Target To Host FIFOs, this feature is useful when you only care
691+
about the latest data and don't care about old data.
692+
"""
693+
return self._get_fifo_property(FifoProperty.FlowControl)
694+
695+
@flow_control.setter
696+
def flow_control(self, value):
697+
if not isinstance(value, FlowControl):
698+
raise TypeError("flow_control must be set to an nifpga.FlowControl")
699+
self._set_fifo_property(FifoProperty.FlowControl, value.value)

nifpga/status.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ def __init__(self, code, function_name, argument_names, function_args):
280280
(-52007, "OperationTimedOut"),
281281
(-52008, "OSFault"),
282282
(-52010, "ResourceNotInitialized"),
283+
(-52012, "EndOfData"),
283284
(-52013, "ObjectNameCollision"),
284285
(-61003, "FpgaAlreadyRunning"),
285286
(-61018, "DownloadError"),
@@ -311,19 +312,31 @@ def __init__(self, code, function_name, argument_names, function_args):
311312
(-63033, "AccessDenied"),
312313
(-63038, "HostVersionMismatch"),
313314
(-63040, "RpcConnectionError"),
315+
(-63041, "RpcServerError"),
316+
(-63042, "NetworkFault"),
314317
(-63043, "RpcSessionError"),
318+
(-63044, "RpcServerMissing"),
319+
(-63050, "TriggerReserved"),
320+
(-63051, "TriggerNotReserved"),
315321
(-63080, "BufferInvalidSize"),
322+
(-63081, "BufferNotAllocated"),
316323
(-63082, "FifoReserved"),
317324
(-63083, "FifoElementsCurrentlyAcquired"),
318325
(-63084, "MisalignedAccess"),
319326
(-63085, "ControlOrIndicatorTooLarge"),
327+
(-63086, "OperationNotSupportedWhileStarted"),
328+
(-63087, "TypesDoNotMatch"),
320329
(-63101, "BitfileReadError"),
321330
(-63106, "SignatureMismatch"),
322331
(-63107, "IncompatibleBitfile"),
323332
(-63150, "HardwareFault"),
324333
(-63170, "PowerShutdown"),
325334
(-63171, "ThermalShutdown"),
326335
(-63180, "InvalidAliasName"),
336+
(-63181, "AliasNotFound"),
337+
(-63182, "InvalidDeviceAccess"),
338+
(-63183, "InvalidPort"),
339+
(-63184, "ChildDeviceNotInserted"),
327340
(-63192, "InvalidResourceName"),
328341
(-63193, "FeatureNotSupported"),
329342
(-63194, "VersionMismatch"),

0 commit comments

Comments
 (0)