Jump to content

DAQmx and wrapping it in classes


Recommended Posts

I'm just curious if any of you have successfully wrapped DAQmx into LVOOP classes (on an application specific level, not wrapping all of DAQmx functionality), and what you have found to be most effective. One thing that troubles me about DAQmx is the lack of safety between the type of acquisition and the DAQmx reads, which manifests itself in run time errors. For example, you may have set up buffered acquisition when you create your virtual channel, but that doesn't stop you from wiring a single point DAQmx read up to your task, resulting in errors at run time. This is just one example. I am not looking for an exact solution, but I am just curious what other people have done in their code with regards to providing themselves with an application specific DAQmx classes. Possible inheritance hierarchies, what pertains to the base class and what pertains to the child classes, if you even care about any of the issues I've stated above in the first place, etc.

Edited by for(imstuck)
Link to comment

This isn't what you're looking for, but it's the beginning of a method I'm trying to refine. It's AF, and it's woefully simple, but it was a starting point for me. In a similar actor that uses visa, when the visa resource name is empty, a child actor is called that allows for simulated/scripted data.

 

StreamDaq.zip

Link to comment

It isn't exactly what I'm looking for but it brings up another point. This is showing an actor that is strictly tied to one type of acquisition: analog acquisition with buffered inputs. One of the things I have issues with when abstracting DAQmx is how to organize the different layers. Should all analog tasks (temperature, pressure, strain) inherit from a base class "analog task?" Maybe, maybe not. Are there enough similarities? Sure, they are all voltage, but what if temperature is only going to be single point, software timed acquisition while the others are buffered? At this point, does it still make sense to inherit? You can no longer have a dynamic dispatch "read" VI because some tasks will return an array, others a single value. So, you can make a polymorphic VI, but then you are back at square one if the wrong instance is selected: run time errors.

 

You could break them off into their own processes for each different type, but now there is no reason to have inheritance at all, because they will all be in parallel. In this case each process manages one, and only one, type of acquisition.

Edited by for(imstuck)
Link to comment
You can no longer have a dynamic dispatch "read" VI because some tasks will return an array, others a single value. So, you can make a polymorphic VI, but then you are back at square one if the wrong instance is selected: run time errors.

You can always just return an array with one element for single values (if a task returns a single value, just use the build array to convert it). Then all your companes are the same. If you really want to, you can wrap that that into a single value polymorphic VI to return just element 0. That way you won't get a run-time error.

Edited by ShaunR
Link to comment
You can always just return an array with one element for single values (if a task returns a single value, just use the build array to convert it). Then all your companes are the same. If you really want to, you can wrap that that into a single value polymorphic VI to return just element 0. That way you won't get a run-time error.

 

I thought about this, but I didn't know if this was a code smell for something that's not correct, causing me to manipulate connector panes purely to force something to work.

Link to comment

Scalar measurement and array measurement sound like different methods, if not different classes.

 

I go back and forth between creating a few classes that cover lots of functionality, and many classes that cover simple tasks. The ones that get reused the most tend to be the simplest (because they're well-understood and they fit easily into any app), and the most complex (because they are the hardest to change - ha!).

Link to comment

You don't have to choose between classes and polymorphic VIs. You can get the inheritance you want, automatic function selection, and you can make it an edit-time error you choose the wrong read and task creation combination. Check out this example of dummy classes.

 

Open example.vi attached here (saved in LV 2012) to get an idea of what I mean. We have done this in our classes before with great success. In fact this can work better than doing Dynamic Dispatch for your reads, because there is no run-time overhead for LabVIEW to determine what Read VI to call. But you still have the flexibility to define your OOP hierarchy.

daq classes.zip

  • Like 1
Link to comment

The questions being asked here are exactly the same questions asked at NI when DAQmx was designed. There were many debates over the trade offs of which way to slice functionality for max polymorphism (which has user advantage insofar as lots of measurements have a similar API) and what to make runtime vs compile-time errors. You see the result. If you're trying to write a *general* OO wrapper, I bet your wrapper will just trade one set of issues for another. But if you design an app-specific API to wrap DAQmx, I know you can put a much easier to use API into place... I know because I've seen users do it.

  • Like 1
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
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.