07-10-2025 09:39 AM
Hello!
I am currently working on developing an application that will interact with various devices using either serial or TCP protocols. This application will also work with DAQ devices, as well as log and monitor collected data. I'm trying to apply OOP principles while developing the application.
I. To begin with, I've created a base class called "Instrument" which includes attributes such as device's name, type, baudrate, timeout, and other relevant information. This class also includes some basic behavior such as opening and closing connections as well as sending commands to the device. There are several child classes that inherit from this base class and override certain methods to provide more specific functionality.
Each device will have unique identifier and is stored in a map for easy access. For each device in the map it will be necessary to create a loop in order to establish communication and perform necessary actions.
My question is, should there be a single subVI (possibly polymorphic) that is called asynchronously for each device, with a shared reentrant clone execution condition activated?
II. I'm struggling with how to approach the DAQ part of the project. There may be multiple tasks (AI, AO, DI, DO) for each device type, and I'm unsure about how to best organize this. My current idea is to create a DAQType abstract class with children. However, I'm not sure if this is the optimal approach. Could you please provide some guidance on this? I have attached a diagram to illustrate my current thoughts.
Class hierarchy example
Some commentary/questions:
I feel like these is some fundamental information that I'm missing. Can you help me to put everything together?
Thank you very much in advance!
07-10-2025 10:35 AM
Hello and welcome to the forum.
Doing DAQ and I/O is what LabVIEW was made for. The DAQtype UML looks like a loose wrapper on some existing DAQmx functionality.
After reading your questions, you might benefit from doing a deep dive into the existing DAQmx functionality in LabVIEW, there is a lot there and it might save you a lot of time. LabVIEW is made to do I/O and the built in library is pretty amazing. Its what makes developing this kind of thing in LabVIEW super fast compared to other languages much of the stuff you are asking about is already written for you, though you might have to write you own UML : )
07-10-2025 11:46 AM
We've been using an OOP approach to hardware at my company for almost 10 years now, so I speak from experience. And my first questions to you would be... are you ever going to use a DAQ that doesn't support DAQmx? And, if not, why are you using LabVIEW OOP for this?
That might seem like a silly questions to ask, but hear me out.
When we started using OOP, our objectives were to:
This went fine and works great for common devices like power supplies and multimeters. Things like setting max volts/amps, toggling output channels on and off, doing single measurements, all very easy to do generically and in a way that obscures the exact connection method and the commands sent.
However, when we got around to DAQs, it became quite sticky. We attempted to create a common set of function calls that could handle anything we needed to do with DAQmx-compatible devices and found that if we truly wanted to be feature-complete we'd essentially have to replicate all the DAQmx calls nearly 1 to 1, and then if we ever found a 3rd party device we'd have to do a lot of creative interpretation of its commands and would likely have to rewrite a ton of things anyway.
As such, we eventually decided to scrap what much of what we'd created, and just create a class for DAQ devices that was essentially all the common features that all instruments had, and then a few calls to pull DAQmx data types out of the stored configuration (tasks, channels, devices, etc.), and then call it good. We'd then just use the class as just a method of folding DAQmx into our standard model, but to go no further. Since DAQmx is already fairly easy to change device types on (going from a CompactDAQ to a PCIe one, for instance) then we already had the functionality we were looking for. DAQmx already works the same whether it's USB or Ethernet or whatever, and we gained nothing but headaches trying to redo it all as a LVOOP implementation.
07-10-2025 11:40 PM
@Kyle97330 wrote:
are you ever going to use a DAQ that doesn't support DAQmx?
I would stress this portion, if you can standardize on the vendor, you can eliminate the need to implement and maintain this DAQ abstraction layer.
You will be investing more into this software portion than you would save on switching between DAQ vendors unless you're purchasing 1000s of DAQs.
07-11-2025 01:52 AM - edited 07-11-2025 02:02 AM
Hello, Jay14159265!
Thank you for your fast reply!
@Jay14159265 wrote:
1. Maybe, you can read the task state form DAQmx methods or make a wrapper and track it yourself.
4. Do you mean swapping out a DAQ card while the system is running?
6. This depends on the use case, are you writing a program or a library? What does the user of the program or library expect?
1. What concept do you mean by wrapper?
4. DAQ-card will still be the same but one group of connected signal lines may be changed to another due to a lack of channels while system is running.
6. Basically, the program should control devices via power sources and track the parameters via DAQ cards. Since the devices operate autonomously for a long period of time, the program also includes cyclograms and PID controls. User expects to be able to monitor parameters and make changes during the operation of a system. There is a possibility that the power sources may also change while peripheral devices (thermocouple, gate, vacuum gauge etc) should not be changed.
I will definitely do the deep dive into the existing DAQmx functionality 🙂 What would you recommend to start with?
07-11-2025 02:21 AM
@Shatoshi wrote:
I will definitely do the deep dive into the existing DAQmx functionality 🙂 What would you recommend to start with?
I think
"Learn 10 Functions in NI-DAQmx and Handle 80 Percent of Your Data Acquisition Applications"
will be a good start followed by the "Advanced Programming" section of
"Getting Started with NI-DAQmx"
07-11-2025 02:36 AM
Hello, Kyle97330!
Thank you so much for such a detailed answer!
@Kyle97330 wrote:
And my first questions to you would be... are you ever going to use a DAQ that doesn't support DAQmx? And, if not, why are you using LabVIEW OOP for this?
There is one device available that does not support DAQmx. I assumed it would be a good idea to use LVOOP if this device is going to be used. In fact, the system can do without this "custom" device. Another reason is that I want to make a scalable application, and based on my Java development experience, I'm trying to apply similar development patterns. It seems like I should change my mindset.
Your answer has cleared up the confusion in my head. I would appreciate it if you could at least give me an approximate idea of what the class for DAQ devices you are using is. Also, based on your experience, can you recommend any sources of information that I could start with?
In the first part of my post, there was also a question about I/O equipment:
Each device will have unique identifier and is stored in a map for easy access. For each device in the map it will be necessary to create a loop in order to establish communication and perform necessary actions.
My question is, should there be a single subVI (possibly polymorphic) that is called asynchronously for each device, with a shared reentrant clone execution condition activated?
Am I thinking in the right way, or am I fundamentally wrong?
07-11-2025 02:42 AM
@UliB wrote:
@Shatoshi wrote:
I will definitely do the deep dive into the existing DAQmx functionality 🙂 What would you recommend to start with?
I think
"Learn 10 Functions in NI-DAQmx and Handle 80 Percent of Your Data Acquisition Applications"
will be a good start followed by the "Advanced Programming" section of
"Getting Started with NI-DAQmx"
Cheers!
07-11-2025 10:34 AM
@Shatoshi wrote:
...
1. What concept do you mean by wrapper?
4. DAQ-card will still be the same but one group of connected signal lines may be changed to another due to a lack of channels while system is running.
6. Basically, the program should control devices via power sources and track the parameters via DAQ cards. Since the devices operate autonomously for a long period of time, the program also includes cyclograms and PID controls. User expects to be able to monitor parameters and make changes during the operation of a system. There is a possibility that the power sources may also change while peripheral devices (thermocouple, gate, vacuum gauge etc) should not be changed.
I will definitely do the deep dive into the existing DAQmx functionality 🙂 What would you recommend to start with?
1. From Wikipedia:
A wrapper function is a function (another word for a subroutine) in a software library or a computer program whose main purpose is to call a second subroutine[1] or a system call with little or no additional computation. Wrapper functions simplify writing computer programs by abstracting the details of a subroutine's implementation.
4. Good, this is the easier case. DAQmx can handle this.
6. So this is an application, you need to provide object interfaces that can be utilized by the UI in a way that makes interacting with each I/O channel homogenous.
Yes, I understand that you are using primarily NI hardware so in your application you can have DAQmx as your base class for tasks and extend the class for instruments that do not use DAQmx. The only bummer is that the DAQmx VIs are not written in LVOOP, maybe someone has a library that has created the wrappers already to make them LVOOP style.
07-11-2025 11:57 AM
@Shatoshi wrote:
Hello, Kyle97330!
Thank you so much for such a detailed answer!
@Kyle97330 wrote:
And my first questions to you would be... are you ever going to use a DAQ that doesn't support DAQmx? And, if not, why are you using LabVIEW OOP for this?
There is one device available that does not support DAQmx. I assumed it would be a good idea to use LVOOP if this device is going to be used. In fact, the system can do without this "custom" device. Another reason is that I want to make a scalable application, and based on my Java development experience, I'm trying to apply similar development patterns. It seems like I should change my mindset.
Your answer has cleared up the confusion in my head. I would appreciate it if you could at least give me an approximate idea of what the class for DAQ devices you are using is. Also, based on your experience, can you recommend any sources of information that I could start with?
In the first part of my post, there was also a question about I/O equipment:
Each device will have unique identifier and is stored in a map for easy access. For each device in the map it will be necessary to create a loop in order to establish communication and perform necessary actions.
My question is, should there be a single subVI (possibly polymorphic) that is called asynchronously for each device, with a shared reentrant clone execution condition activated?
Am I thinking in the right way, or am I fundamentally wrong?
That is what I do. I have one non-reentrant part that scans for all instruments and makes a map of device information, model, sampling rate, etc. I use the instrument alias as the key. The user enters the parameters for an Analog Input acquisition, and this non-entrant VI configures all the task parameters in the map. Once the task is configured and committed, it is sent to a reentrant VI that starts the task. This reentrant VI allows one to change the display, analysis, etc of the running task. Thus multiple devices can run at once.
I do not know if this is the correct way, but it works.