Jump to content

How to manage RT code with FPGA refs that runs on Win/Linux/Mac


Stobber

Recommended Posts

I have an RT app. A pretty big one. It does a lot of stuff.

 

I have a Windows app that talks to my RT app. In the interest of dividing labor, creating automatic unit/subsystem tests, allowing multiple devs to build on their own machines, etc. I need to be able to simulate the RT program on Windows.

 

So I abstracted all the calls to NI-RIO using Conditional Disable Structures and added a "Simulator" VI that wraps the entire application while hooking into some custom messages so it can display information to the user. When I need to run on Windows, the RIO calls don't execute and the Simulator panel ties into the network connections. When I need to run on RT, the Simulator panel isn't called and the RIO calls execute. It works great....except on machines that don't have the LVFPGA module installed (because they only develop the Windows app). Even though the ConDis structures prevent code from being called, it still gets statically linked into the app. This prevents a Windows-only system from building the Windows app: it throws errors while looking for FPGA Module components.

 

What's the best way to abstract the FPGA reference wire from the code to work around this? I hate the idea of creating a class hierarchy for my IO calls and dynamically loading the class at runtime because dynamically launched code is nearly impossible to debug on LVRT.

Edited by Stobber
Link to comment

We created something similar.

 

We first put all FPGA communications into sub-VIs.  Then we created a simulation loop for the RT where we called a model VI instead of the actual IO vi.  Because we kept the FPGA reference encapsulated within the sub-VI, any code which didn't actually make use of the VI ran fine.

 

So I would recommend simply encapsulating the communications to your FPGA target and things work better.

Link to comment

So I would recommend simply encapsulating the communications to your FPGA target and things work better.

 

Huh? How? By wrapping them in subVIs? That still statically links to the NI-RIO xnodes. I need a way to dynamically load the code that calls NI-RIO at runtime.

 

I ended up turning my IO API library into a class and abstracting it from the application with the Factory Pattern, but it took a lot of dumb boilerplate code, and now there's quite a bit of code duplicated between the Physical IO class and the Simulated IO class. I still hate it, but it works for now.

Link to comment

Huh? How? By wrapping them in subVIs? That still statically links to the NI-RIO xnodes. I need a way to dynamically load the code that calls NI-RIO at runtime.

 

I ended up turning my IO API library into a class and abstracting it from the application with the Factory Pattern, but it took a lot of dumb boilerplate code, and now there's quite a bit of code duplicated between the Physical IO class and the Simulated IO class. I still hate it, but it works for now.

 

You create VIs that contain those refnums but you load and call them dynamically through Open VI Reference and (Asynchronous) Call by Reference (CBR)! Usually I create the VI that does the work and a wrapper VI that does the Open VI Reference and (A)CBR and Close Reference.

 

You can make the wrapper as smart as you like adding the logic to decide if it should attempt to load the VI or just bail out without doing anything (or creating a warning or something) in there. Also I usually do some smart caching for the refnum using an uninitialized shift register to prevent opening and closing the refnum over and over again. Last but not least although not very nice from a design point of view I tried in the past to combine multiple operations in one wrapper/dynamic subVI combination since maintaining lots of these in parallel is quite a work load.

 

Another better approach I have considered but which failed in the past with older LabVIEW versions because of some LVOOP limitations is to use the dynamic dispatch feature of LVOOP. You would then create two (or more) classes for the different platforms and a dummy base class and load the appropriate child class dynamically (with Get LV Class Default Value.vi) at start and then call it through the interface provided by the base class. This is IMHO the most clean design for such things. It basically uses the Factory Pattern here.

 

While I'm not yet converted to LVOOP for everything, I find the Factory Pattern a very elegant design method to solve problems where you have dynamic components that you need to access depending on some condition that has to be determined at runtime. Doing it through VI server with (A)CBR is certainly an option but LVOOP dynamic dispatch makes it that more elegant.

Link to comment

Or just use dumb VIs and a conditional disable......

 

Conditional disable while allowing a VI to run despite unrunable code in disabled frames can have some strange effects. For one, LabVIEW normally tries to load the VIs anyhow which can result in dialogs during loading for missing subVIs and such. Also there have been strange and hard to reproduce problems with the error list showing errors that only go away after removing and recreating the code in conditional disable frames.

Link to comment

That's interesting Rolf,

 

any external links to that subject?  We make great (as in a lot, not as in good) use of Conditional disable structures in our code at the moment and I find it quite unwieldly even without calculating in bugs and such....

 

This is one topic, but there are more and I've seen some weird errors too especially with the conditional disable structure in the General Error Handler.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.