LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How do I debug a VI with a class input

I have created my first hardware abstraction using classes, and it works great. However, when debugging subVIs that take this class as an input, I'm not sure how to proceed. With a VISA input, any prior initialization of the device remains active, and I can test my subVI by providing the VISA connection data (an IP address for example). Not sure how this works with classes.

 

My first pass at this is to have a step in the sub VI that does the class initialization, if the class is not initialized. If I wanted to do this on every run, how can I check if a class instance has already been created? One thing I found I can do is read some value in the class data which would only be available after the class is created. But there a better way?

 

 

_____________
Creator of the BundleMagic plugin for LabVIEW!
0 Kudos
Message 1 of 4
(158 Views)

I developed a class-based hardware library starting about 10 years ago so I know the pain you're talking about.  It's a necessary part of using classes though; by their nature they have to be set up programmatically inside their own class since you can't write to a class wire without being a member.

 

Essentially, what I have done is that for every class I have 3 VIs that I include in every class, ready to drop on a temporary subVI any time they are needed.

 

The first two subVIs are interchangeable depending on need.  One converts a single JSON string into a fully populated instrument reference, allowing me to save an instrument configuration on disk or in a database, or as a string constant.  The other one is a single VI with every possible pre-initialization input for the class being an input on the subVI (for instance, it might include a VISA address, baud rate, list of sensors attached to the device, and a toggle whether or not to reset on startup).  Either of these allow me to create and populate the class variables.

 

The 3rd one is just an initialize VI that all instrument class members must create.  It connects to the instrument and runs anything that also needs to populate inside the class data.  For instance, if the instrument driver is for a "series" of power supplies, it might get the exact model number as well as the maximum output of that supply and store that in the class reference.

 

So whenever I want to debug an individual command, I do this:

 

1. Control-N for new temporary VI

2. Drop one of the 1st two subVIs to set up the configuration, add any needed inputs

3. Drop the 3rd VI to do the initializing

4. Drop the VI that needs debugging

5. Wire them all together

6. Iteratively run the temporary VI while doing normal debug stuff on the problem VI, whether that's probing, breakpoints or other methods.

 

 

Message 2 of 4
(141 Views)

Thanks Kyle97330, really helpful stuiff!

 

For my current use case, I keep all the instrument setting in a yaml file (say no to JSON configs!), so I am able to provide a yaml key to my Class Init VI. I've gone ahead and coded up a debug VI that checks to see if the class was initialized (by reading some state data, though I still want a better way), and then instantiating the class and initializing the instrument if needed. Someday maybe I'll need something more complex like you describe.

_____________
Creator of the BundleMagic plugin for LabVIEW!
0 Kudos
Message 3 of 4
(135 Views)

@littlesphaeroid wrote:

a debug VI that checks to see if the class was initialized (by reading some state data, though I still want a better way), and then instantiating the class and initializing the instrument if needed. 


In my implementation, there's an "Initialized" Boolean that's one of the members of the private data of the top-level class.  The read accessor for it is public scope so any code can check on it, but the Write accessor is not. 

 

I originally had it set to Protected, and each class was supposed to write a True to it during its initialization as part of its startup.  Later, I made that write accessor Private, and changed the settings for the Initialize VI to be a required VI that also must call its parent unconditionally, then put that private accessor in the top-level Initialize VI override. 

 

This let me add in arbitrary "hooks" that I could call on each instrument initialization.  In addition to just setting the Initialized Boolean, it also:

  • Logs the initialization, if the calling application has previously run a different VI that sets up logging (i.e. the log file path, and what to log)
  • Checks the instrument class for a couple pieces of required data, generating an error if it's missing
  • Generates a user event containing the instrument reference and a few other bits of data as the event data
  • Adds the instrument to a list of instruments initialized so far on that run

 

Doing all that is overkill for your current setup though, but if you plan on using your class in a lot of applications in the future, try to leave the possibility open to do things like this by not having weird workarounds like inferring initialization from state data, but rather explicitly setting it and making it difficult or impossible to forget to set it.

Message 4 of 4
(110 Views)