Stobber Posted August 15, 2014 Report Share Posted August 15, 2014 (edited) 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 August 15, 2014 by Stobber Quote Link to comment
shoneill Posted August 18, 2014 Report Share Posted August 18, 2014 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. Quote Link to comment
Stobber Posted August 19, 2014 Author Report Share Posted August 19, 2014 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. Quote Link to comment
Rolf Kalbermatter Posted August 19, 2014 Report Share Posted August 19, 2014 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. Quote Link to comment
shoneill Posted August 19, 2014 Report Share Posted August 19, 2014 Or just use dumb VIs and a conditional disable...... Quote Link to comment
Rolf Kalbermatter Posted August 19, 2014 Report Share Posted August 19, 2014 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. Quote Link to comment
shoneill Posted August 19, 2014 Report Share Posted August 19, 2014 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.... Quote Link to comment
Rolf Kalbermatter Posted August 19, 2014 Report Share Posted August 19, 2014 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. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.