LabVIEW Development Best Practices Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Hardware Communication and LVOOP

Hello all,

For a while, I have been considering refactoring some of my early LVOOP attempts at what are for all intensive purposes device drivers.  In the current iteration, my devices are generally broken out by communication method - i.e. serial, DAQ, GPIB, etc.  I have never really liked this approach because of how heavily coupled the device is to the communication platform.  The problem with this approach is that I have several devices that can communicate via multiple paths (and are currently used in this manner).  For instance, I have a high voltage power supply which in one instance uses GPIB to communicate and in another has uses simple analog input and output.  And, here is where some of the complexity becomes very apparent in this problem: while they share the same basic functionality (get/set voltage), one form of communication has a much more extensive set of communication possibilities (i.e. the GPIB can do many things such as turn off/on, check status, etc.).  Up until now, I haven't been able to get past the forest for the trees so I have not been successful at coming up with a solution.  But, I am starting to come up with a couple of ideas that are starting gel and I wondered if anyone had any thoughts.

The overarching scheme would be something like this:

sketch struct.jpg

where you have a generic Device class that anticipates some type of communication with hardware, regardless of how the communication is accomplished.  In this instance, it is composed of a Comm object and has two public methods that are common to all children: Init for initialization of the device and Shutdown for proper closure of the device.  The Comm class is an abstract class whose children will specify exactly how communication occurs and similar to the Device class, has two public methods that all children will override that are the correllaries to the two in the Device class.  At this point, most of the details are not present as this is just the skeleton (you can envision the Serial object having properties specific to serial communication such as port, etc).

Now, related to this implementation, I have two questions: first, does this look like a reasonable way of going about this?  And second, what would be the best way to structure all of this to send commands and retrieve data to/from the Device object?  I can think of a couple of possibilities such as having a command message class/data class that can be consumed by the appropriate implementation of the Comm class or having concrete implementations of the Comm children that directly correspond to the concrete implementation of the Device class.

Please let me know if this is utterly unclear.  Any thoughts are appreciated (including this is a terrible idea).

Thanks, Matt

0 Kudos
Message 1 of 6
(5,835 Views)

Matt,

imho this is all but a 'terrible idea'!

Maybe not fully thought (sorry, my english, I mean thinking not finished)), but a very usefull approach.

Some years ago I tried to start using an LVOO approach for DMMs and programmable power supplies PPS's, but could not come to a result superiour than my conventional approach. But maybe the global structure of that approach can be of help for you, so I'll explain it a bit:

For my app, I have

* a generic '...DMM_Measurements.vi' that simply gets a 2D-array of continuous measurements of given length and the preset configuration.

* a generic '...Configure DMM....vi' that sets the kind of measurement, channels, sample rate(s), range(s) ... whatever

* a generic '... detect DMM....vi' that detects the actually connected specific devices with their connection ports and some specific limits

* Init and Shutdown-VIs

The generic VIs simply use case-structures to execute specific code depending on the detected device.

A similar approach is used for the PPS's, having the generic 'methods' Set voltage(volts, channel, on/off) and configure(channel, Umax, Imax)

--

Greetings from Germany!

LuI

0 Kudos
Message 2 of 6
(3,812 Views)

Thanks, Lul.  It appears that you were solving a similar problem in a non-OOP manner.  Here are some more thoughts concerning what I am actually attempting to do (although I think that most people who build data acquisition systems understand this problem to a certain extent).

This application extends your DMM example in two ways: first, we are not only dealing with different types/makes of devices which make the same fundamental measurements but rather we are also potentially using devices that make fundamentally different measurements.  This gets to the core of what the Device object represents and brings into question the intended scope of the object.  In the broadest sense, a 'Device' is simply the software representation in the data acquisition system of a piece of hardware that makes a standalone measurement with which we must communicate externally (i.e. send/receive signals) through some type of communication protocol to control/monitor the device.  This would potentially exclude integrated cards such as PCI, PXI, cDAQ, etc which might be used to facilitate communication with these devices.  Some specific examples from my own work: heaters, thermoelectric coolers, flow controllers, power supplies and other miscellaneous pieces of custom hardware (which in turn might be defined more broadly as instruments - those devices which themselves make important standalone measurements).

The second difference (although you may be attempting to do something similar) is that here we are trying to make the same fundamental measurements via different communication protocols.  A couple of examples of this:

  • A mass flow controller that can communicate via RS232 and analog IO
  • A high voltage power supply that can communicate via GPIB and analog IO (this is currently what is motivating the reexamination of my approach)

And with regards to this point, I see a couple potential paths to go down as far as handling communication.  The first path would be to make concrete, device specific implementations of the Comm object which will mirror the concrete Device implementations.  The second would be to have generic get and send methods for communication which take some type of command object that would be specific to the device.  I will have to sketch these out, but I am curious to see what others think about these approaches or if there is another that I am not considering.

Anyway, thanks a lot for the response Lul; it was helpful.  I apologize for the long winded response.  Hopefully I will have more details in the next couple of days.

Cheers, Matt

0 Kudos
Message 3 of 6
(3,812 Views)

OK - so I may be putting myself out.  Essentially, if we offload all of the communication to the Comm class via some kind of messaging, then it is unclear to me what value the actual "Device" class has.  Essentially, the "Device" remains generic - you can initalize the device (usually open a connection and send some preliminary commands), send and receive data and close the "Device" (which will send any final commands and then close the connection).  It's not clear to me how this any better than simply subclassing the Device class (as I had originally done) and coding the communication protocol into the subclasses.

sketch struct.jpg

0 Kudos
Message 4 of 6
(3,812 Views)

Matt,

in the end, each device instance has its own command set. And if the devices command sets are similar in one or the other degree, at least the properties are different. So if you really use your abstract Comm class, you can probably not have  abstract methods for init, shutdown whatever without taking into account the private properties of the instantiated device. So the only think your Comm class can do is doing the actual transfer of control signals to the device, which is already supported by LabVIEW and the OS it runs on.

I can not really see the use case for a generic device class, as ANY device is used for some specific case. And most if not all devices do not have a generic 'action' that do not need a specific property. Referring to my solution, There is no generic 'Do Your Job' for the DMM nor the PPS. The most generic actions for PPS are 'set output to voltage', 'set output to ON/OFF' and 'configure device' with device or device class specific properties. For the DMM this is 'measure voltage', measure current', ... and 'configure device' with a totally different set of properties than that for the PPS. Even simpler DMMs and more powerfull ones might have quite different sets of properties. So at the end of the day, what is your generic device used for?

--

Greetings from Germany!

LuI

0 Kudos
Message 5 of 6
(3,812 Views)

Hey Lul,

I think that you may be misunderstanding the concept of abstract here.  The Comm object does nothing by itself, i.e. it must be subclassed in order to be used.  That at the heart is what an abstract class is.  In fact, I can define abstract Init and Shutdown methods that must be overriden by children classes.  That would be part of the contract that all users would have to satisfy to use this class.  I think, aside from any other actions, we can agree that all devices to some extent must be properly initialized and shutdown; the precise details of how this occurs is left up to the child of the abstract parent.

And, I think that I can show you some use cases for 'generic' devices (I do this now for serial devices).  To suggest that there is no fundamental measurement for a device such as the DMM seems incorrect to me.  In the end, ask exactly what you want from that DMM - a voltage (maybe current, maybe both), no?  This may be returned as a single value or an array, but either way, you want some type of measurement that is specific to the DMM (which will not be flow or temperature or pressure, etc, etc).  Sure, how you retrieve it will be different for different DMMs, and likely you can request other types of data or send other commands, but when you purchase a dedicated piece of hardware such as a temperature controller or a flow meter or a power supply, you have a very specific purpose that can be satisfied by multiple vendors.  You can even boil these ideas down further and remove the context by simply saying you want a float or an integer from the device and you will provide a boolean or a numeric value to it.  But, ultimately, what you want is a generic DMM class that will return voltage (how it does this and what other commands it might also ingest will be left up to the children).  In the implementation, you would call the generic DMM 'get voltage' not really caring how it does it, just knowing that you get what you want.  This is abstraction.

The abstraction from a DMM can be extended further to a single abstraction of multiple devices and there are numerous benefits to do this. To see the benefits of a fully developed hardware abstraction layer, check out NI's white paper on HALs.  You can also see an example of HAL implementation in Elijah Kerry's wonderful demonstration of an MVC using the Actor Framework. 

Cheers, Matt

0 Kudos
Message 6 of 6
(3,812 Views)