04-25-2017 08:23 AM - edited 04-25-2017 08:25 AM
I am having a problem when trying to take an OOP approach to coding my RT. I will briefly describe my setup and aims, then talk about some solutions I can see. I would really appreciate it if someone could recommend another, better way to tackle this!
I have an FPGA on a PXIe connected over the backplane to the controller running RT which is connected to a host PC over Ethernet. I have several DMA FIFO memories (Wave, Event, etc.) defined in the FPGA vi that I want to interact with on the RT. In the case of each memory there are several functions I want to do; pollBuffer, parseEvent and sendToHost being typical. So I am taking an object orientated approach and defining my memories as classes and my functions as methods of these classes. To maximise code reuse I want to keep the methods as general as possible.
So, I want to write a method called pollBuffer. This method will read a specific DMA FIFO and write the data found therein to another buffer on the RT. In my mind the approach is obvious; I want to pass a reference to the DMA FIFO and a reference to a RT buffer to a generic method. The type of data in the classes is all consistent as U64. The problem comes when I try to use the invoke method node. When I wire the full FPGA vi reference (i.e. contains references to all FPGA items) to this node, I use a drop down menu to select the memory and the method (read, write, etc.), but this fixes the node to the DMA FIFO in question; it is no longer generic.
I can create a reference constant, configure it based on the FPGA vi and then delete references to every other DMA FIFO item leaving just a single DMA FIFO. When I wire this to the invoke method node, the node still requires manual configuration to the memory (e.g. Wave) and the method (e.g. Read). Furthermore, when I convert this constant to a control and wire it to an input on the connector pane, this control is type defined to a specific memory. i.e. if I subsequently wire a FPGA vi reference constant with a different DMA FIFO only to this input of this method then there is a type clash.
So now onto workarounds and solutions...
It appears that I cannot use DMA FIFO references dynamically in my RT code. So I could write a different method in each class (1 class for each memory) which contains the appropriately (manually) configured invoke node to read the appropriate memory. This is not code reuse!
I could try to use polymorphic vi's to get the input wire to the class method to accept different FPGA vi reference types, but this would involve writing a different polymorphic vi for each reference type. The same number as the solution above. No code reuse! Plus it appears I cannot make a method, with dynamic dispatch inputs necessary for classes, which also has a polymorphic vi, this throws an error! The workaround to the workaround here would be to package the polymorphic vi within the class method as a separate vi. This seems like even more work than the first solution!
So, neither solution seems to be compatible with OOP. Both seem to require writing a different method for each class, as least for the DMA FIFO buffer read operations.
Later on I am planning to use references to other RT FIFO memories to perform other methods, such as parseEvent and sendToHost. These methods will also differ only in the references to the appropriate RT FIFO, but it does seem that these references are also type defined to specific RT memories! So I might not be able to use my dynamic reference approach here either!
Does anyone have any better ideas how I can efficiently code my RT?
Many thanks in advance!
04-26-2017 01:18 PM - edited 04-26-2017 01:20 PM
It has been a while since I looked at this, but I believe there is a way, albeit it a bit of work, to create a reusable framework given the support already there. You alluded to a similar set of classes already, so perhaps this is what you already tried.
Essentially, you should first define the generic interfaces you want to represent in your framework. Try to make the underlying implementations, such as the FIFO, storage, etc. being used pluggable using something like a set of factory or builder methods when creating the derived implementations of those generic interfaces. For instance, if you have a protocol/mechanism that has two input FIFOs and two output FIFOs, have the Create factory method take abstract FIFO implementations for the input and output ports.
At the lowest level, you'll have to create one derived class for each FPGA interface FIFO or Memory, and override the basic Read and Write methods that will be hard-coded to a specific "Named" transfer type. The Create method for this class would take a specific FPGA host interface and capture it as state internally. The instantiated derived class is then passed to the builder/factory for your higher-level framework creation code as the implementation of a particular transfer connection.
While this takes a bit of work to get set up, if you have standard naming conventions for your resources, you'll quickly build up a set of "reusable" plugin classes that can be used behind the scenes interchangeably.