Dropping-In on the Testbed

Last time out we started exploring one common application of so-called “drop-in” VI. The technique is based on the idea of creating VIs that are capable of performing something useful for the VI that is hosting it, but without interacting directly with that VI’s basic logic. The example we considered was manipulating the font and type size used to present textual data.

At the close of that post we has created a basic object-oriented structure that could manipulate the label or caption of any front panel control or indicator. I want to finish this discussion by looking at how to expand that basic implementation to allow it to set the text properties of text contained inside a control or indicator. For that we will return to our testbed application.

A Brief Recap

It has been a while since we have worked with this code, so a brief refresher on what it does is probably in order. The testbed application we will be modifying consists of several processes that run independently of one another. To begin with, there is a background process that oversees the reporting of errors that occur. Handling the user interface duties, a GUI process incorporates a subpanel that can display the front panels of several simulated acquisition and process-control VIs. The whole thing is kicked off by a launcher VI that loads the various processes into memory and starts them executing.

Our goal here will be to add the drop-in VI we created last time to all the user-facing VIs and add classes as necessary to allow it to handle the controls and indicators on those VIs. However, if you don’t already have a tool for editing database contents directly, you should first download a tool called Database .NET (the link is to a zip file, and is at the bottom of the page). The program is a simple utility that lets you examine and edit database data from a number of different DBMS. I don’t know the folks that wrote this, and have no vested interest in the program other than I have used it for years and found it very useful. Note that this program has no installer so it has a very small footprint – it will even run from a USB stick. To “install” the program, simply create a directory for it on your computer and then drag into it the program that is inside the zip archive you downloaded, and installation is complete. The easiest way to invoke it is to set it as the default application for *.mdb files.

  • Note that if you decide to install this utility in a subdirectory of the Program Files (x86) directory, you may have to play around with the folder permissions a bit before it will run. Because the program generates several temporary files when it’s starting up, the user has to have Full Access to the folder in which it is installed.

One other caveat to bear in mind before we dive into the modifications is that, these operations cannot override limits on these properties that might exist for other reasons. For example, these techniques will not work on controls that you have defined as strict typedefs. The reason: The strict typedef defines everything about the control’s appearance and the property node will throw an error if you try to change them. Likewise, a System-themed control will let you change the font characteristics, but will complain if you try to change colors.

Making With the Modifications

So where do we start? Well the first hing we need to do is to make a couple minor tweaks to the Display Font Manager.vi. First, we need to define what happens to the drop-ins errors. Because it’s important to preserve them, we will save the errors that arise in the drop-in to the same location that errors from the testbed application proper are stored – but without bothering the program’s operator. To accomplish that task, let’s reuse a the subVI that the error handling logic uses to store error data.

Drop-in Error Handling

Note that I had to add a case structure because the location where this subVI was originally used only executed if there was an error. So unless we want to have spurious records being posted, we have to add that logic here.

Next, as the code is currently written, the error chain in the drop-in’s logic starts with the Error In control and terminates in the Error Out indicator. Although this arrangement works fine during development and testing, when the time comes to deploy the code, this is not what we want. As I said last time, drop-in VIs should not interact with the host VI and should not inject their own errors into the host’s error stream. Still, it can be useful to be able to use the drop-in’s error IO to establish data dependencies that control when it runs. The solution is for the drop-in to have error clusters, but not have them be connected internally.

Errors - Straight Through

Changing the Testbed

Now that we are to install the drop-in, we need to look for where to install it. Completing that examination of the code, we see that there are 5 VIs that are user-facing:

  1. The Launcher (testbed.vi)
  2. The Main GUI (Display Data.vi)
  3. The Temperature Controller (Temperature Controller.vi)
  4. Two “Acquisition” VIs (Acquire Ramp Data.vi and Acquire Sine Data.vi)

So the first thing I do is modify each of these VIs by dropping a copy of the drop-in VI on to their block diagram outside the outer-most loop. For example, this is what the modified launcher block diagram looks like:

textbed.vi with drop-in installed

As promised earlier, this is all the modification that the application will need – which means we are ready to start testing.

The First Test

“But wait a minute…” you protest. “…we haven’t configured anything yet. There’s nothing to test!”

Well you’re half right. We have not gone into the database and configured any controls to be modified, but we still have something to test. We still have to verify the drop-in’s default behavior, which by the way, is to do nothing. Yes, you read that right, we have to test that nothing happens. You see, a major aspect of the drop-in concepts is that drop-ins don’t do anything unless they are explicitly told to through their configuration. Right now we have installed the drop-in code, but there are no controls configured in the database so we need to make sure that the main application continues to run as it did before: no side-effects and no errors. In short, the drop-in right now should do nothing, and we need to make sure that it fulfills that requirement.

So launch the top-level VI (testbed.vi) or run the standalone executable. As before, the launcher will show the names of the processes it’s launching and when it finishes the main GUI will open. Again as before, you will be able to switch between screens using the popup menu and the plugins will operate just as they did before. Finally, if you look at the contents of the event table in the database, you will see that no errors have been generated.

It’s All About the Children

Now that we have “nothing” working, we need to finish implementing all the “somethings”. You will recall that when we ended last time I had created a basic implementation of the font manager functionality that could change the label or caption of any type of control. The tricky part, I said was going to be implementing the subclass, or children, methods that would modify the font of a configured control’s contents. So let’s look at those children.

The String and Digital Subclasses

I choose to start with these two because they are the easiest to understand, and are very much alike. Here’s the child method for handing strings…

String Subclass Method

…and the one for digital numerics…

Digital Subclass Method

In either subclass, the logic starts by calling the parent methods (which handles labels and captions) and then extracting from the parent’s class data the reference to the control that will be manipulated. At the same time that is going on, the Font Parameters data is unbundled and the Component to Set value controls what, if anything, happens next. If the selected component is Label or Caption a case is selected which does nothing but pass through the error cluster. If, however, the selected component is Contents the associated case casts the basic control reference from the parent class data into the control’s specific control class, and then sets the appropriate properties.

The Boolean and RingSubclasses

The next two I want to consider are, again, similar each other, but differ from the preceding pair in that they represent control classes that don’t have any readily discernible textual value. Booleans represent logical true and false conditions, while rings are technically numerics, but the number that is their value doesn’t appear anywhere. In this sort of situation, the idea is to look for text that is not the control’s value but is associated with that value. For example, Boolean controls in LabVIEW can have textual displays that state the control’s condition. These strings are called Boolean Text and are often used to label push buttons or lights…

Boolean Subclass Method

Likewise, the Ring control appears to the user as a pop-up menu, so we can use this code to set the text properties of the text that appears in the menu…

Ring Subclass Method

The WaveformChart Subclass

Finally, we need to take the idea of strings that are only associated with data one more step. What about complex controls that can have multiple strings associated with their values? Objects like charts are good examples of what I am talking about. Just to start, there is text associated with the axis tick marks, there is text that forms the axis labels, and there is text in the plot legends.

The most flexible approach would be to figure out how to uniquely identify each of these components, however we must be careful to not create an API that is so flexible that it is unusable. One solution would be to simply make all the text the same font and size – which is what they are anyway. A look that I prefer however is to have the tick mark labels slightly smaller than the axis labels. Here is one way to do that:

WaveformChart Subclass Method

As you can see, the code treats the two axes the same by combining references to them into an array and then passing that array into a loop that manipulates the display parameters. This logic makes the axis labels the size specified in the configuration, but does a bit of math to make the tick mark labels about 10% smaller. This difference might not seem like much, but it works. If this isn’t exactly what you want, that’s OK. The point here is not to present a canonical solution, but to present concepts and ideas that help you find your own way.

Adding Configurations

Now we are ready to add the font definitions to the database. I have created a total of 12 definitions covering 9 different controls and indicators and you can see them all by examining the SQL file in the _repos subdirectory in the project (starting at line 27). However, to give you a taste of what the SQL code for this functionality looks like, here is the SQL for the table holding the font configurations, and the font definition for the string indicator on the front panel of the launcher.

CREATE TABLE ctrl_font_definition (
    id          AUTOINCREMENT PRIMARY KEY,
    owner_name  TEXT(50) WITH COMPRESSION,
    ctrl_name   TEXT(50) WITH COMPRESSION,
    font_name   TEXT(20) WITH COMPRESSION,
    font_size   INTEGER,
    ctrl_comp   TEXT(20) WITH COMPRESSION
  )
;

INSERT INTO ctrl_font_definition
  (owner_name, ctrl_name, font_name, font_size, ctrl_comp)
VALUES
  ('testbed.vi', 'progress', 'Segoe UI', 24, 'Contents')
;

The goal of these initial definitions is to “turn-on” the functionality without changing too much. For example, the ‘Segoe UI’ font is the default font that LabVIEW uses on recent versions of the Windows platform. If you are running this code on the Macintosh or Linux (or an older version of Windows), the default font will be different. So on other platforms you may need to modify these definitions before you install them.

Once we have the definitions in the database, let’s try the testbed application again. You might not notice a lot of difference, that is sort of the point. This initial test is to reproduce the default values. One place where you will notice a difference is if you are running Windows and you have the display font scaling on your display set to the non-default value. The text size will now always be the same relative to the size of the window regardless of how the display setting changes.

From here I would recommend that you play around a bit and manually change the font and size of the various controls to see the effect.

Testbed Application – Release 16
Toolbox – Release 12
Testbed Installer – Release 16

Please note that I have included in this release a built version of the application so you can practice working with the database. The LocalDB.mdb file included with this installer has the table defined for holding the font definitions, but the table is empty. This release has two purposes: One, by adding to and manipulating the data in its database, you can see that you really can modify the visual presentation without changing code. Two, I have started using LabVIEW 2015 and realize that some of you may not have upgraded yet. If this version change is a problem, post a comment and I will send you a version of the code back-saved to LabVIEW 2014.

The Big Tease

One of the things that I like about NI Week is the opportunity to meet friends both new and old. Before a keynote address one morning I was talking to another one of the LabVIEW Champions, Jack Dunaway by name, and the topic of this blog came up. To make a long story short, he suggested a topic that sounded so good, I’m going to get started on it next time.

One good of way showing a lot of data in a small space is what is known as a tree control. It’s valuable because its structure is inherently hierarchical and so can display a lot of data while not taking up a lot of screen real estate. In addition, it can reduce the overwhelm that you sometimes feel when looking at large datasets because, when done well, they allow you to start with a high-level view of the data and gradually drill down to the specific results you want.

If you are working in Windows, there are two such controls available: one that is part of Windows, and one that is native to LabVIEW. So next time: the Native LabVIEW Tree Control. Be there or be square.

Until Next Time…

Mike…

Drop-Ins Are Always Welcome

One of the key distinctions of web development is that the standards draw a bright line between content and presentation. While LabVIEW doesn’t (so far) have anything as powerful as the facilities that CSS provides, there are things that you can do to take steps in that direction. The basic technique is called creating a “drop-in” VI. These functions derive their name from the fact that they are dropped into an existing VI to change the display characteristics, but without impacting the host VI’s basic functionality.

The Main Characteristics

The first thing we need to do is consider the constraints under which these VIs will need to operate. These constraints will both assist in setting the scope of what we try to accomplish, and inform the engineering decision we have to make.

No Fraternization

The first requirement that a VI to meet in order to be considered truly “drop-in” capable, is that there must be no interaction between its logic and that of the VI into which it is being dropped. But if there is to be no interaction with the existing code, how is it supposed to change anything? Given that we are only talking about changing the aspects of the data presentation, all we need is a VI Server reference to the calling VI, and that we can get using the low-level Call Chain function.

VI Server Accesses

As you can see, from the VI reference you can get a reference to the VI’s front panel, and from that you can get an array of references for all the objects on the front panel. It is those references that allow you to set such things as the display font and size – which just happen to be the two things we are going to be manipulating for this example.

One potential problem to be aware of is the temptation to use these references to do things that directly affect how the code operates. However, this is a temptation you must resist. Even though it may seem like you “got away with it this time”, sooner or later it will bite you.

To be specific, changing the appearance of data is OK, but changing the data itself is, in general, not. However, there is one exception that when you think about it makes a lot of sense: localization. Localization is the process of changing the text of captions or labels so they appear is the language of the user, and not the developer. This operation is acceptable because although you might be changing the value in, for example, a button’s Boolean text you aren’t changing what the button does. The button will perform the same whether it is marked “OK”, “Si” or “Ja”.

Autonomous Error Handling

The next thing a drop-in has to be able to do is correctly manage errors. But here we have a bit of a conundrum. On the one hand, errors are still important, so you want to know if they occur. However, you don’t on the other hand, want this added functionality to interrupt the main code because an error occurred while configuring something the user would consider as “cosmetic”.

The solution is for the drop-in to have its own separate error reporting mechanism that records errors, but doesn’t inject them into the main VI’s error chain. The error handling library we have in place already has the needed functions for implementing this functionality.

External Configuration Storage

Finally, the drop-in VI needs configuration data that is stored in a central location outside the VI itself – after all, we want this drop-in to be usable in a wide variety of applications and projects. For implementing this storage you have at your disposal all the options you had when creating the main application itself, and as with the main application, the selection of the correct storage location depends on how much of this added capability will be exposed to the user. If you intend to let the user set the values, you can put the settings in an INI file. You just need to make sure that you quality the data they enter before you try using it. Otherwise you could end up in a situation where they specify a non-existent font, or a text size that is impossibly large or small.

To keep things simple for this test case, we will store the data in the same database that we use to store all the other configuration values. The data that we store in the database will also be (for now) simple. Each record will store the data needed to modify one part of one control, so it will contain a field for the name of the VI, the name of the control, an enumeration for selecting what part of the control is to be set, and finally the font name and size. The enumeration Component to Set will have 3 values: Label, Caption and Contents. Note that to keep things organized and easy to modify or expand, this structure as a whole, and the enumeration in particular are embodied on the LabVIEW side in type definitions.

The Plan of Action

So how can we implement this functionality? The literary device of the “omniscient author” has always bothered me so rather than simply heading off in a direction that I chose before I started writing, let’s take a look at a couple of implementation options and see which one of the two will work the best for us. Remember that the only thing more important that coming up with the right answer, is knowing how you came up with the right answer.

The “Normal” Way

For our first try, let’s start with the basic logic for getting the control references we saw a moment ago, and add to it a VI that returns the font configuration data for the VI that is being configured. Note that the input to this fetch routine (which gets the data from the application database) is the name of the VI that is calling the drop-in. This name is fully qualified, meaning it contains not just the VI name, but also the names of any library or class of which it might be a member.

Font Manager - Deadend

The output from the database lookup consists of a pair of correlated arrays. Correlated arrays are arrays where the data from a given element in one array correlates to, or goes with, the data from the same-numbered element in the other array. In this case, one array is a list of the control names and the other array is a list of all the font settings that go with the various parts of that control.

The first thing the code does is look to see if there are any font settings defined for the VI by checking to see if one of the arrays are empty. It is only necessary to check one of the arrays since they will always have the same number of elements. If there are font settings defined for the VI, the code takes the array of control references from the VI’s front panel and looks at them one-by-one to determine whether the label for that particular control or indicator is contained in the array of control names. When this search finds a control that is in the list of control names, the code unbundles the font settings data and uses the Component to Set value to select the frame of a case structure that contains the property node for the specified component’s property.

This approach works pretty well for labels and captions because all controls and indicators can, regardless of type, have them. In addition, regardless of whether the control is a string, numeric, cluster or what have you, the properties are always named the same. (The property for manipulating a control’s Caption is shown.)

Unfortunately, things begin to get complicated once you move past the properties that all controls share in common and start changing the font settings for the data contained inside the control – what we are calling the Contents. For example, the property for setting the font of the contents of a string control is called Text.FontName, whereas the property for setting the corresponding information in a digital numeric is called NumText.FontName. Things get even stranger when you start talking about setting the font of the Boolean text in the middle of a button, or worse the lines in a listbox – there each row has to be set individually.

The fundamental problem that this simple approach has is that the settings for controls and indicators are built on object-oriented principles. Labels and Captions are easy because they are common to all controls, but as soon as you start talking about text that is contained inside a control, you have to deal with a specific type, or subclass, of control. Plus to even get access to the required properties you need to cast the generic Ctl reference to a more specific class like a Str (string) or DigNum (digital numeric). We could, of course, simply expand the number of items in the Component to Set enumeration to explicitly call out all the various components that we want to be able modify. Then in each case we could do something like this:

'fixing' a problem

Because we know that the String Text is only valid for strings, we could cast the reference to the proper subclass, set the appropriate property, and call it done. If you look at very much code you will see this sort of thing being done all the time. But looking closer in those situations you will also see all the code that gets put into trying to fix this implementation’s shortcomings. For example, because the subclass selection logic is in essence being driven by the enumeration, and the enumeration value is stored in the database; we have created a situation where the contents of the database needs to be kept “in sync” with the controls on the front panels. Hence if a string control should be changed to a digital numeric (or vice versa) the database will need to be manually updated to track the change. This fact, in turn, means that we will need to add code to the VI to handle the errors that occur when we forget to keep the code and the database in sync.

As bad as that might sound, it is not the worst problem. The real deal-breaker is that every time you want or need to add support for another type of control, or another Component to Set, you will be back here modifying this VI. This ongoing maintenance task pretty much means that reusing this code will be difficult to impossible. Hopefully you can see that thanks to these problems (and these are just the two biggest ones), this “simple” approach built around a single case structure ends up getting very, very messy.

But if the object-oriented structure of controls is getting us into trouble, perhaps a bit more object orientation can get us out of trouble…

Riding a Horse in the Direction it’s Going

When programming you will often find yourself in a situation where you are wanting to extend a structure that you can see in a way that you can’t yet fully see or understand. When confronting that challenge, I often find it helpful to take some time and consider the overall trajectory of the part of the structure I can see to see where it’s pointing. Invariably, if you are working with a well-defined structure (as you are here) the best solutions will be found by “riding the horse in the direction it’s already going”.

So what direction is this “horse” already going? Well, the first thing we see is that it is going in the direction of a layered, hierarchical structure. In the VI Server structure that we can see, we observe that the basic control class is not at the top of the hierarchy, but rather in the middle of a much larger structure with multiple layers both above and below it.

Menus

The other thing we can note about the direction of this architectural trendline is that the hierarchy we just saw is organized using object-oriented principles, so the hierarchy is a hierarchy of classes, of datatypes. Hence, each object is distinct and in some way unique, but the objects as a group are also related to one another in useful ways.

Taking these two points together it becomes clear that we should be looking for a solution that is similarly layered and object-oriented. However, LabVIEW doesn’t (yet) have a way to seamlessly extend its internal object hierarchy, so while developing this structure using classes of our own creation, we will need to be careful to keep “on track”.

Moving Forward

The basic for this structure is a class that we will call Display Properties.lvclass. Initially this class will have two public interface VIs: One, Create Display Properties Update Object.vi, does as its name says and creates an object associated with a specific control or indicator. This object will drive what is now the only other interface VI (Set Control Font.vi) which is created for dynamic dispatch and will serve as the entry point for setting the font and size of text associated with GUI controls and indicators. I am building the class in this way because it is easy to imagine other display properties that we might want to manipulate in the future (e.g. colors, styles, localization, etc.). This is the code I use to dynamically load and create display property update objects:

Create Font Object

In general, it is very similar to code I have presented before to dynamically create objects, but there are a few differences. To begin with, the code does not buffer the object after it is created because unlike the other examples we have looked at over the past weeks, these objects do not need to be persistent. In other words, these objects will be created, used and then discarded.

Next, to simplify in their identification, all VI Server classes have properties that return a Class ID number and a Class Name. The code uses the latter value to build the path and class name of the child class being requested.

Finally, after the code builds the path and name of the subclass it wants to use, it checks to see if the class exists and only attempts to load it if the defining lvclass file is found. If the file is missing, the code outputs a parent class object. The reason for this difference is twofold:

  1. Without it, if a control class was called that we had not implemented, the code would throw an error. Consequently, in order to prevent those errors I would have to create dozens of empty classes that served no functional purpose – and that is wasteful of both my time and computer resources.
  2. With it, the logic extends what normally happens when a method is not overridden in a subclass, to include the case where the subclass hasn’t even been implemented yet: the parent class and, – more to the point – the parent methods, are invoked.

Taken Care of Business

The dynamic dispatch VI Set Control Font.vi is obviously the parent method for what will eventually be a family of override methods that will address specific types of controls. But that begs the question: What should go in this VI?

Well think about it for a moment. In the first possible implementation we looked at, things initially looked promising because changing the font and size of labels and captions was so easy. You’ll remember that the reason they were easy, was because all controls and indicators can have them and the properties are always named the same. That sounds like a pretty good description of what we would want in a parent method – so here it is:

Set Font Parent

The structure is pretty simple, the code retrieves the control reference from where it was stored in the class data and passes it into a case structure that has cases for Label and Caption. In addition, it has an empty case that handles the Contents value of Component to Set. This case is empty because that value will be handled during override. So all we have left to do for right now is look at how these VIs look incorporated into the structure we looked at earlier – all we really needed to replace was the case structure…

Font Manager

…and here it is. Nothing much new to see here, so let me just recommend that you take a good look at this code because you probably won’t be seeing it again. Since we will be adding functionality in the context of the class structure we created, we won’t need to revisit this logic any time soon, and maybe ever.

The Big Tease

So with the basic structure in place, all we have to do is start populating the subclasses we need. But that will have to wait for next time when I will also post all the code.

Until Next Time…

Mike…

Creating a Reconfigurable Interface Using Undockable Windows

Something I have always enjoyed doing is creating programs or interfaces that do things you don’t expect LabVIEW to be able to do. Consequently, I thought I would take a couple posts and consider some useful and perhaps surprising interfaces.

The first one I want to look at is actually an idea I got from another LabVIEW Champion – Ben Rayner by name. Some time ago, he posted on the user forum a small proof-of-concept VI for an interface that is so cool I though I’d polish it up, flesh it out and see what came out of it.

What it does

At first glance, the interface appears similar to the test bed application that we have built on this blog. There is a common display area and by making selections from a pop up menu, you can display screens showing different data.

docking single screen

The difference is that if you click a button, the GUI will “undock” the current screen and turn it into an independent floating window that is no longer accessible from the popup menu.

docking 3 screens

The software allows an operator to undock as many screen as they want at one time. The only limitations are screen space and logic that mandates leaving at least one screen docked. Likewise, if you close one of the floating windows, it will again take up its original position in the selection menu. As is our usual policy, a link to the code is a little further along in this post.

Why This Interface?

I fully plan to get into how the code works, but first we need to consider why you would want to use this interface in the first place. What is the use case that this interface addresses?

Hopefully it should be obvious to anyone who considers the matter for more than a moment or two that user interfaces are always compromises. If you do your due diligence when designing an interface you try to put together in one screen or window the various bits of information that are logically related, or at least will be used together. However, requirements can change, or a particular type of user might need to be able to correlate pieces of data that are on different screens.

You could create a separate screen for just that user, but that solution requires some additional development effort. However, if you create windows that can be undocked to be moved around the screen as desired, users that want to see their data in a particular way may be able to do so without waiting for you to create a custom screen.

So with all that in mind, let’s think about how we might accomplish this sort of GUI.

How it Works in Theory…

The first thing to you need to realize as we begin looking at how to create this interface, is that if you have been following this blog you already know everything required to make this happen. The only thing missing is an understanding of how to make all the pieces fit together in a slightly different way.

For example, we have talked many times about how to create a basic multiscreen interface using subpanels. Likewise, we know how to make windows float on top of one another by defining their behavior as floating. Now if you think about it, these are the two states that our screens can be in: as a subpanel (when docked) and as a floating window (when undocked).

So our problem is really as simple as deciding how to manage the transition from one state to the other. If you are following the recommendations I have been making, the screens are already written as separate processes that don’t know (or care) how they are being displayed – or even if they are being displayed.

So how do we want this to behave? Well for the undocking there are a variety of options. LabVIEW supports drag-and-drop so we might be able to do something with that. Alternatively, we could create a pull down menu with an “Undock Current Window” on it, or even a custom shortcut menu when the user right-clicks on the on the interface’s front panel. But those are really just different ways of triggering the same logic, so for this demo I’m just going to create a button below the subpanel that is labeled something obscure like, “Click to Undock the Current Display”.

For docking one of the floating windows back in the interface, our options are more limited. But when you have a really good technique available, you only need one. How about this: when you click the window’s close button it gets docked back into the interface. After all, it’s what most users would try anyway.

…and in Practice

Now that we basically understand where we are going, lets start looking at some code.

Undockable Windows – Release 1
Toolbox – Release 9

The block diagram of the top-level VI is pretty much what a regular reader of this blog would expect. It starts by running a subVI that loads into memory, and starts executing, all the VIs that are going to be available through the subpanel. References to these VIs are stored in a DVR so they can be used later to populate the subpanel itself. This subVI also outputs an array of strings that are the names of the VIs it loaded. The code uses this array to initialize the strings in a ring control, and then programmatically fires the value change event associated with the ring.

initialization for undocking

With this work done, the VI next registers to receive a UDE that we will discuss in a moment, and enters the program’s main event loop. This loop includes a value change event for the ring control that changes the VI that is visible in the subpanel, and two additional events that manage the undocking and docking processes.

Getting Undocked

The first of these new events handles the undocking of windows and, understandably, is a value change event on the undocking button. The event logic goes about its work in two steps that are contained in separate subVIs. The first one is called Float the VI.vi.

undock

Its job is to remove the VI that is being undocked from the subpanel using the Remove VI subpanel control method, and then (after looking up its VI reference in the DVR) open its front panel using the FP:Open VI method. The other half of the operation is performed in Process Undock.vi.

process undock

This VI’s purpose is to update the user interface to the VI’s change of state – which in this case means simply disabling its selection in the ring control, and updating the DVR. This subVI is also responsible for getting a reference to the next available docked window and inserting it into the subpanel. As a by-product of this operation, the subVI also generates a flag that indicates when there is only one docked window remaining. The event handler uses this flag to disable the undock button when all but one of the displays have been undocked.

Docking a Window

Like the previous one, this event handles its duties as a two-step process. But unlike the previous one, it is driven by a UDE from the VI that is being docked back into the main display. As stated before, this action should be triggered when the user closes the VI’s front panel. The plugins accomplish this task by intercepting the Panel Close? event and instead of closing its front panel, simply fires a UDE (Redock Screen) that tells the GUI to reincorporate it back into the subpanel. The first subVI in the event handler is Unfloat the VI.vi.

redock

After looking up the VI’s reference in the DVR, it closes the VI’s front panel and inserts it back into the subpanel. Note that it is not necessary to remove the VI that is already there. The other subVI that the event handler calls is Process Redock.vi.

process redock

Basically reversing the operation that were performed when the window was undocked, this VI removes the window’s name in the ring control from the list of disabled items and updates the status stored in the DVR.

The Big Tease

So there’s a basic implementation of a pretty neat capability, but what now? What sort of enhancements might we reasonably want to make? I have an idea. You notice that when the window’s undock, they always open in the middle of the main screen. This is certainly a reasonable approach, but an enhancement that would be sure to make your users happy is to provide some sort of mechanism whereby each window would remember its last position. With that capability in place a windows would reopen in the same place as it was when it was last closed.

So when we next get together, let’s do that. It will be a good thing to know how to do in general.

Until Next Time…

Mike…

Using VI Server to Interact with Executables

We all want to be able to reuse code and a good way of accomplishing that goal is by repurposing executables that you wrote for other projects. The problem is how you control them. Last week we started addressing this challenge by looking at some of the general tools that are at our disposal for manipulating executables — regardless of where you got them. This time out we will complete the discussion by looking at some of the things you can do that are specific to LabVIEW-created executables.

First, we need an executable

As the title says, if we are going to talk about making VI Server calls to an executable, the first thing we need is an executable — and an executable, we have. Although the functionality it implements is, to be honest, rather sparse, it is sufficient to demonstrate what we need. Here’s what its front panel looks like:

A Small Test Executable - FP

Starting in the top left, it sports an indicator where you can see the command line that was used to launch it. Immediately below that string is an indicator showing the current time, a button for stopping the program manually, and a pair of LEDs that indicate when two different events are triggered: Application Instance Close? and Panel Close?.

To the right is a path indicator that displays one of two different paths depending on the state of the checkbox that is next to it. Below the path indicator are two numerics. One is the PID of the instance that is running. The other is the TCP/IP port number that was assigned to the executable when it was launched. Note that if you don’t provide a port number in the command line parameters, the executable will terminate almost immediately — though you may see it briefly appear in the Windows Task Manager.

Handling the front panel

Most of the code that makes this interface work is pretty straight forward, so I won’t take the time to describe it. The one exception is this bit in the initialization logic:

Intialization Logic

The reason that I’m pulling it aside for special attention is that it illustrates (at least part of) the solution for a problem that you will encounter the first time you create a VI that is designed to run entirely in the background. The heart of this problem is mismatched expectation: When LabVIEW runs an executable it expects to open the window associates with the top-level VI. You, on the other hand, wanting the executable is run unseen in the background, expect the window to stay closed. Consequently, what happens is that LabVIEW opens the window and starts the VI running in that order and your code immediately hides the front panel. What the user sees is a windows that open and then immediately closes without explanation, and if there is one things that worries users more than things happening too slowly, its things happening too fast — like windows flashing open and then closing.

The solution lies in a VI property called Transparency. The setting to control it can be found in the custom appearance dialog.

Transparency Dialog

When the box is checked and the percentage is set to 100, the window will be open but totally transparent. Hence, when the runtime engine launches the application, the window will still open but it will be invisible. A moment later, the code above will hide the window and set the transparency to 0 so that when we do decide to open it, we will be able to see it.

VI Server Operations

Last time, I presented this block of settings from the application’s INI file. Before we continue, we need to take a moment all consider what these settings mean — at least to the extent that anyone knows what they mean…

server.tcp.enabled=True
; server.tcp.port=3363
; server.tcp.serviceName=""
server.tcp.acl="290000000A000000010000001D00000003000000010000002A10000000030000000000010000000000"
server.vi.access="+*"
server.vi.callsEnabled=True
server.app.propertiesEnabled=True
server.vi.propertiesEnabled=True
server.control.propertiesEnabled=True

The first four parameters in this list control overall access to the application via TCP/IP. Consequently, they are the four that you are most likely need to muck with:

  • server.tcp.enabled=True: This setting enables the TCP/IP interface that VI Server uses. If this setting is False, nothing is happening.
  • ; server.tcp.port=3363: This setting specifies the port that the associated TCP/IP listener will be monitoring for a connection. Note that I have this line commented out because we will be assigning this value via command line parameter.
  • ; server.tcp.serviceName="": Also commented out, this optional parameter allows you to define a name that you can then use to reference the application, instead of a Port number.
  • server.tcp.acl=???: This setting defines the TCP/IP access control list (ACL) — or who is allowed to connect to the application. Already I can hear you wondering, what is the deal with that long string? Well, if you ever find out be sure and let me know. The bottom line is that the original interface included an ACL that simply listed the IP addresses that were and were not allowed to access the application. For reasons unknown, NI decided to change this common sense approach to something more enigmatic. So how do you generate this string? Glad you asked. According to LabVIEW’s documentation, you need to set up your development environment to have the same access list as you want your application to have, and then copy and paste the resulting string from LabVIEW’s INI file to your application’s INI file, seriously…

The remaining parameters specify in one way or another the specific resources that the remote program can access in the target application.

  • server.vi.access="+*": This parameter contains a list of VIs that are accessible through the VI Server interface. The default value shown allows access to all VIs.
  • server.vi.callsEnabled=True: This parameter specifies whether the remote program is allowed to run VIs contained in the executable. We leave this True so I can demonstrate that ability.
  • server.app.propertiesEnabled=True: This parameter gives the remote program access to the executable’s application-class properties — like the names of all the VIs currently in memory.
  • server.vi.propertiesEnabled=True: This parameter gives the remote program access to the VI-class properties of individual VIs. This category include things like a reference to the VI’s front panel.
  • server.control.propertiesEnabled=True: This parameter gives the remote program access to the properties associated with individual controls on VI front panels. For example, you need to have this parameter enabled to do things like programatically set the value of a control. This value is True as I will be demonstrating this ability as well.

Finally, I want to state one thing that I hope is obvious. All these “security” settings are contained in a plain text file that can be edited by anyone who knows how to use a simple text editor. The point here is that while recent versions of Windows are making it harder and harder to modify files in the “Programs” directories, it is not by any stretch of the imagination bullet-proof. Hence, if there are truly sensitive things that need restricted access, don’t depend on these settings.

What we can do with these controls

So let’s put some of what we have been learning about into action. If you download the code from the SVN repository you will find, in addition to the source code, a compiled executable. For the following tests, you can either run the executable I have included, or compile it on your own — it’s up to you. You will also want to be sure to update your copy of the toolbox as I have added a couple useful VIs. One of the executable management VIs is where we will start:

Launching the Executable

Start by opening small test executable.lvproj and then open the routine Launch 3x.vi. It’s job is to launch three copies of the test application (small test executable.exe) so on the front panel click the path browser button next to the path control and navigate to and then select the test application. Now, run the VI.

When it finishes, launch the Windows Task Manager. Nothing new under Apps, or Programs (depending on your version of Windows), so look in the Background Processes. Ah, there’s the executable, but why is it listed here? And why is there only one instance? The VI clearly looped 3 times, and there were no errors. Go to the directory where the test application is located and open its INI file. There are your answers. There is only one instance running because the INI file has multiple instances turned off, and the one executable that did launch shows up as a background process because the INI file also says to hide the root window. Leave the root window setting the way it is, but change the AllowMutipleInstances to True, and save and close the file.

Now back in the Task Manager, abort the one instance of the test application that is running now, and rerun Launch 3x.vi. You should see when it finishes that there are now 3 instances of the test application running. The instances were given sequential TCP/IP port numbers from 3365 to 3367.

Firing Remote Events

The next thing I want to do is open the front panels of the 3 instances so we can observe their operation. Now if you look at the test application’s source code, there is a UDE that will make the front panel visible, so all I need to do is fire that event. But wait, those are three instances of a compiled executable — you can’t fire events in other executables! Well actually, you can. To see how, open the test VI, Open the Executable’s Window.vi.

Open Executable Front Panel

No magic here. All the code is doing is dynamically running a VI. But check out the function before Open VI Reference, it’s called Open Application Reference. Its job is to open a reference to a copy of LabVIEW or the LabVIEW runtime engine that is running somewhere else. That “somewhere else” is defined in terms of a machine name and a port number or service name. The machine name can be a DNS name, an IP address or (as in our case here) localhost to point to the local computer.

By the way, if you think it sounds like I just said that you could make this same code access an executable residing on a remote computer by simply changing localhost to an IP address, your right. I did just say that.

But as cool as that feature might be, how does it allow me to fire an event in a compiled executable? Look at the name of the file being run: Open Window.lvlib:Generate Event.vi. It’s the VI that fires the event, and since VIs called in this way actually execute in the remote LabVIEW environment, the event gets fired in the targeted executable.

To see this code in action, run it three times with the port number 3365, 3366 and 3367. Three windows will open.

Setting Control Values

Another way of interacting with an executable is to directly manipulate controls on its front panel. However, if the target VI is event-driven like our test application, we need to remember that there is a difference between setting a value and firing any value change events associated with that control. If all you need to do is set a value, there is a VI method called Control Value:Set that will do the job nicely. However, if you want to fire the value change event you have to set the control’s Value(Signaling) property — which frankly is a bit more work.

set the selector control value with signalling

This picture is the block diagram of the test VI Toggle the selector checkbox.vi, but the good news is that for this little bit of extra effort, you can set (or read) any control property that can be changed while a VI is running.

Shutting Down the Executable

Finally, we need to be able to stop an application that is running. But the problem here is figuring out how to test it such that we can see that it really did what it was supposed to do. The solution is to turn to the trace technique we discussed a while back when we were learning about command line arguments. I have written the code such that if the executable is run with the argument “d1” in the command line, the code will write a line to the trace file saying how the instance was stopped. And to help demonstrate how this works, I have created a test VI (Stop the Executable.vi) that can execute some of these termination paths.

To start off, leave both controls in their default state, and run the VI. This example stops the targeted executable by clicking the Stop button on its front panel. The instance with the port number 3365 will immediately close.

Now increment the Port Number to 3366 and set the Method control to Windows shutdown - Forced. This example stops the targeted executable by telling to Windows to abort it. The instance with the port number 3366 will immediately close.

Finally, we want to test the remaining instance’s response to the Application Instance Close event. To do that, restart your computer now. (That’s right, restart your computer. Don’t stop anything, don’t shut anything down — just restart.) When your computer is restarted and you are logged back in, go to the directory where the test application is installed and open the trace file. You will see two lines that look something like this:

07:29:39 05/24/2015 -- Shutdown 3365 -- Just Stop
07:42:52 05/24/2015 -- Shutdown 3367 -- Appl Inst Close

The second line shows that when you restarted your computer Windows did in fact generate the Application Instance Close? event and the application caught the event. You’ll note that there is no entry for the instance with the port number 3366. Remember, we stopped it by forcing an abort and a Windows abort is very much like clicking the red abort button when LabVIEW is running a VI: It just stops. No orderly shutdown. No deinitialization.

A Small Test Executable — Release 1
Toolbox — Release 9

The Big Tease

So that was, I hope, interesting. Starting next time I’m going to start delving into how to use LabVIEW code as the data collection and control backend for an application that has as its only customer-facing interface a web site. While there are many companies offering options that claim to be developer-friendly I have found that many of the marketing claims are largely based on FUD (Fear, Uncertainty and Doubt). Simply put, they build up a “strong man” of supposed complexity and complication, and then tell you that the best (and perhaps, only) way to get past this obstacle is to buy their product. The truth, however, is that their “strong man” is really made of straw, and if you understand how it all fits together, doing it yourself isn’t really very hard.

Until Next Time…

Mike…

Raising the Bar on Dynamic Linking Even Further

Important: Before we get started this week, if any of you have downloaded the code from last week and have had problems with it, please update you working copy with what is currently in SVN. In working on this post, I found some “issues” — including the significant problem that the database that defines everything didn’t get included in the repository release. The current contents of the repository should fix the problems, and I am sorry for any hair-loss and/or gnashing of teeth these problems might have caused.

Also, be sure that if you plan to run this code in the development environment that you name the directory where it is located “testbed”.

These days, the most common way of implementing the dynamic calling of VIs in LabVIEW is through the Start Asynchronous Call node. In addition to being efficient, this technique is also very convenient in terms of passing data to the VI that is being called. Because it replicates the VI’s connector pane on the node, all you have to do is wire to terminals. However, this convenience comes at a price. For this type of call to work you have to know ahead of time what the connector pane of the VI being called looks like. This constraint can be a problem because it is not uncommon for situations to arise where you are wanting to dynamically call code the connector pane of which varies, is irrelevant (because no data is being passed), or is unknown. As you should by now be coming to expect, LabVIEW has you covered for those situations as well.

Where There’s a Will, There’s a Way Method

Over the years as LabVIEW developed as a language, its inherent object orientation began to become more obvious. For example, when VI Server was introduced it provided a very structured way of interacting with various objects within LabVIEW, as well as LabVIEW itself. With VI Server you can control where things appear on the front panel, how they look and even how LabVIEW itself operates. Although it didn’t reach its full expression until the Scripting API was released, the potential even existed to create LabVIEW code that wrote LabVIEW code.

We won’t be needing anything that complex, however, to accomplish our goal of dynamically launching a VI where we don’t have advance knowledge of its connector pane. In fact the part of VI Server that we will be looking at here is one of the oldest and most stable — the VI object interface. Just as you can get references to front panel controls, indicators and decorations, you can also get references to VIs as a whole.

Like control references, VI references come in two basic forms: strict and non-strict. To recap, a strict control reference contains added information that allows it to represent a particular instance of the given type of control. For example, a strict cluster control reference knows the structure, or datatype, of a particular cluster. By contrast, a non-strict cluster reference knows the control is a cluster, but can’t directly tell you what the various items are that make up the cluster.

In the same way, strict VI references, like we have been using to dynamically launch VIs, know a great deal about a specific class of VI, including the structure of its connector pane. This is why the Start Asynchronous Call node can show the connector pane of the target VI. However, as stated earlier, this nice feature only works with VIs that have connector panes exactly matching the prototype. As you might suspect, the solution to this problem is to use a non-strict VI reference, but that means we need to change our approach to dynamic launching a bit. Instead of using a special node, we’ll use standard VI Server methods to interact with and run VIs.

Mix and Match

To see how this discussion applies to our testbed code base, consider that to this point we have used a single technique to launch all the processes associated with the application. Of course to make that approach work required one teeny tiny hack. Remember when we added to the data source processes an input that tells them “who they are”? Well, that modification necessitated a change to the VIs’ connector panes, and because we were launching all the processes the same way, I had to make the same change to all the processes — even those that didn’t need the added input, like the GUI and the exception handler.

So big deal, right? It was only one control, and it only affected 2 VIs. Well maybe in this case it isn’t a huge issue, but what if it weren’t 2 VIs that needed to be changed, but 5 or 6? Or what if all the various processes needed different things to allow them to initialize themselves? Now we have a problem.

The first step to address this situation was actually taken some time ago when the launcher was designed to support more than one launch methodology. You’ll remember last week when creating the dynamically launched clones, we didn’t have to modify the launcher because it was written from day one to support reentrant VIs. What we have to do now is expand on this existing ability to mix and match VIs with launch methodologies to include two new options in the Process Type.ctl typedef. Here’s what the code for the first addition looks like:

run method - nonreentrant

As before, we start by opening a reference to the target VI, but this time it’s a non-strict reference. Next, we invoke the Run VI method, which has two inputs. The first input specifies whether we want to wait the target VI to finish executing before continuing, and we set it to false. The second parameter is named somewhat obscurely, Auto Dispose Ref. What it does is specify what to do with the VI reference after the VI is launched. In its default state (false) the calling VI retains the VI reference and is responsible for closing it to remove the target VI from memory. In addition, if the calling VI retains the reference to the dynamic VI, when the caller quits, the dynamic VI is also aborted and removed from memory. On the other hand, when this input is set to true, the reference is handed off to the target VI so the reference doesn’t close until the dynamic VI quits — which is what we want.

The other new launch option is like the first, except it connects the option constant that tells the Open VI Reference to open a reference to a reentrant clone. Other than that, it works exactly the same.

run method - reentrant

So with these two new launch methodologies created, all we have to do is change the database configuration for the GUI and Exception Handler processes to use the nonreentrant version of the Run VI method and we are done right? Well not quite…

One of the “quirks” of the Run VI method is that although it does start a VI executing, if that VI is configured to open its front panel when run (like our GUI is), the open operation never gets triggered and the front panel will stay closed. The result is that the VI will be open and running, you just won’t be able to see it.

To compensate for this effect (and the corresponding effect that the front panel won’t automatically close when the VI finishes), we need to add to the GUI a couple VIs from the toolbox that manage the opening and closing of the GUI’s the front panel.

open front panel

That’s the opener there, the last one in line after all the initialization code. This placement is important because it means that nearly all the interface initialization will be completed before the front panel opens. The result is much more professional looking. By the way, this improved appearance is why I rarely use the option to automatically open a VI’s front panel when it is run.

close the front panel

And here is the closer. The input parameter forces the front panel closed in the runtime, but allows it to stay open during development — a helpful feature if there was an error.

Where do we go from here?

So that is the basics of this technique, but there is one more point that needs to be covered. Earlier I talked about flexibility in passing data, so how do you pass data with this API? Well, we ran the VI using a method, so as you would expect, there is other methods that allow you to read or set the value of front panel controls. This is what the interface to the Control Value Set method looks like.

the set control value method

It has two input parameters: a string that is the label of the control you want to manipulate, and a variant that accepts the control’s new data value. Note that because LabVIEW has no way of knowing a priori what the datatype should be, you can get a runtime error here if you pass an incorrect datatype. Obviously, using this method your code can only set one control value at a time so unless you only have 1 or 2 controls that you know you will need to set, this method will often end up inside a loop like so:

set control value in a loop

…but this brings up an interesting, and perhaps exciting, idea. Where can we get that array of control name and value pairs? Would it not be a simple process to create tables in our database to hold this information? And having done that would you have not created a system that is supremely (yet simply) reconfigurable. This technique also works well with processes that don’t need any input parameters to be set. The loop for configuring control values passes the VI reference and error cluster through on shift registers and auto-indexes on the array of control name/value pairs. Consequently, if a given VI has no input parameters, the array will be empty and the loop will execute 0 times — effectively bypassing the loop with no added logic needed. By the way, this is an important principle to bear in mind at all times: Whenever possible avoid “special cases” that have to be managed by case structures or other artificial constructs.

More to Come

Over two consecutive posts, when have now covered two major use cases for using dynamic linking: VIs that will run as separate processes. But there is another large use case that we will look at the next time we get together: How do you dynamically link code that isn’t a separate process, but logically is a subVI?

Testbed Application &mdash Release 12

Toolbox — Release 6

Until next time…

Mike…

Managing Shared Resources in a Subpanel-Based Interface

We have seen that building a system out of autonomous interacting processes can be a powerful architectural concept. However, there can be opportunities to simplify the operation of the system as a whole (and make it more robust) by designing one of those interacting processes to create common shareable resources that can be reused throughout system.

This time out we will consider a couple simple ways to implement this functional reusability without creating a brittle application.

Creating Reusable Resources

So the first thing we need to do is figure out exactly what we mean by “Reusable Resources”. In a sense we are creating a reusable resource every time we build a reusable library of drivers or functions, but that sort of reuse is not what I am talking about here. The distinction is that things like libraries are for really tools for the developer and users seldom even realize they exist. What I am talking about in this post are aspects of the program that are user facing.

For example, say you have an application that has 4 or 5 screens and they all need a couple buttons and a menu or two, but the buttons and menus on each screen do different things. One solution would be to simply duplicate the button and menu logic on each screen. but there are limitations to what you can do in this way. To begin with, forget the idea of having menus. Windows in subpanels technically aren’t open, so they don’t have menu bars and can’t have menus.

A far more flexible solution is to let the main GUI carry these reusable, or shared resources and let the subpanel VIs interact with them via references. Right now, that approach will be the focus of our attention.

Basic Concepts

One of the beautiful aspects of VI Server is that it allows you to do nearly anything with references that you can do directly. Therefore, our basic approach will be to pass references to the shared resources to the subpanel VI when it becomes active (i.e. visible in the subpanel) so it can register for, and respond to, the events associated with those resources. As a demonstration of how this works, we’ll add a button and a very simple menu example. The menu example will be simple because I am planning a complete discussion of menus for later time.

A New Requirement

The application to this point has provided a means for looking at data, or at least simulated data. It does not, however, have the ability to store any data. What we want to add is the ability to press a button, or make a menu selection, and have the data source we are looking at save the current chart contents to a text file. In addition, to raise the bar a bit higher, let’s also include in this requirement that the button and menu have to reconfigure themselves based on which data source is selected. In other words, if we are looking at the sine data source, the button and menu should say something like, “Save Sine Data”, or if viewing the ramp data, “Save Ramp Data”.

So what do we need to do to implement this functionality? To answer that question, let’s consider what we know. We know that a big reason for using subpanels in the first place is to eliminate data transfers. Therefore the data needs to be saved from the acquisition process itself — what would be the point of moving it somewhere else first?

Moreover, if each process is going to be handling its own data, doesn’t it make sense to let it handle the button clicks and menu selections too? The alternative is for the GUI to detect the button click or the menu selection and, in response, generate another event of some kind to let the acquisition processes know what happened. But there is no benefit to having the GUI acting as a middle man, mediating the communications. Better to go with the simple way.

And this is how you do it:

Dynamically Managing Events

If the easy way to handle this requirement is to let the acquisition processes handle the buttons and menus, we are going to need a way to turn events of all kinds on and off — not just timeouts. After all, there are three acquisition processes and we only want one of them at a time managing the shared resources.

To see how that works, let’s revisit for a moment how you register dynamic events. Here is a typical snippet of code (in fact, a subVI named (re)create reuse events.vi) that is registering a couple events. The basic idea is pretty simply. You wire a reference of some kind to the node and LabVIEW will show you the specific events that you can associate with that reference. In this case, we are creating a value change event from a Boolean control reference, and a menu selection event derived from a VI reference.

zombie event builder

By the way, if you plan on building this subVI from scratch, be aware that this situation is one of the few places where LabVIEW cares about the order in which you wire things. To duplicate my results, first create and name the input controls, then wire them to the Register for Events node, finally create the output event refnum indicator, and then duplicate it to create the corresponding input. Once you have the subVI (or at least me implementation of it), this is what it looks like installed into one of the acquisition processes. It’s the one with the red banner across the top.

initializing zombie events

If you are observant you might be wondering how this is going to work because neither of the reference inputs that the subVI uses to create the registration, are connected to anything — which means that the references they are passing to the registration node aren’t valid. The thing is, when LabVIEW creates an event registration it doesn’t check for the references to be valid. Used in this way, the references only have two functions: Define the type of reference associated with the event, and name the event.

This fact is important because it is central to what we are trying to accomplish. As long as the references associated with the registration are invalid, the events are in essence turned off because you can’t fire an invalid event. To turn them on, all you have to do is modify the registration to use valid references. This snippet shows how I have modified the Change Source event and its event handler.

change source with sequence frame

First, I moved the My Name control outside the event loop because I an going to be needing it several places. Second, I modified the event data to pass three references in addition to the name of the source being selected. Two of those references relate to the values we used to initialize the registration. The third reference is a menu reference that we will discuss in a bit. Third, I modified the event handler such that if My Name matches the selector string from the event data, the registration is recreated using the two real references, thus allowing this VI to receive those two events. If My Name does not match the selector string from the event data it executes an instance of the registration VIs that has no references wired to its inputs. Fourth, what in the world is that single frame sequence structure with the wires passing through it for?

In the finished code you will see a subVI sitting there, but I wanted to pass on a tip. Many times when working I will realize that I will need a subVI that I haven’t created yet. To allow me to continue work, I will drop down a single frame sequence structure and wire up the data inputs and outputs that I know it will need. Once that it done, I turn it into a subVI by selecting it and then choosing the Create SubVI option from the window’s Edit menu. As a reminder that I have to go back and finish it, I will leave the new subVI with the default icon.

We’ll get to what this mystery VI does in a bit. But it should be obvious that these changes are useless if there are no error handlers, so I added them in too. Here is what the handler for the button press looks like.

save button key press

We first call our little library function to pop the button back out (since we obviously can’t have the terminal for the button here) and then calls a new subVI to save the data to a text file. This is what the data saving VI looks like on the inside:

data save subVI

Note the comment I put in the code. I will be wanting to come back and reimplement this data saving better so I put a bookmark in the code to remind me.

We are also going to need an event handler for the menu event as well, but before we can build that code, you need to know a bit more about how menus work in LabVIEW.

The 411 on Menus

As I stated before, I am going to devote an entire post to menus in the near future, so the following discusses a very basic implementation.

The first thing you need to know about menus is that to create and manipulate runtime menus you need a menu reference — no surprise there. Unfortunately, LabVIEW doesn’t treat menu references like it does references to other parts of a VI. For example, if you need a reference to VI’s front panel, you can get it from a reference to the VI. Not so with menu references. The only way to get a menu reference is from a special node that has to reside on the block diagram of the VI that will be showing the menu. This “quirk” is why we need to pass two different references to the subpanel VI that both deal with menus: the VI reference allows us to register an event for the menu, but we need the menu reference in order to make changes to the menu contents.

Next, you need to know that every menu item has a Name and a Tag. In many ways these properties are analogous to a control’s Caption and Label. Like a control’s label, a menu item’s tag cannot be changed dynamically because it is the way that LabVIEW uniquely identifies that particular object. However, the menu item name is the visible string you see when you operate the menu and (like a control’s caption) can and often does change during the execution of an application.

Here is the code in the GUI that will define our very basic menu and its three items. Note that I have packaged this logic in a subVI so when I upgrade the menu generation, it will be easier to do. Remember that a good principle for when to make something a subVI is to ask yourself is this functionality (or the implementation of the functionality) likely to change?

building simple menus

Breaking down the logic, the first node deletes all the existing menus. The next node creates a new top level File menu. Finally, the third node is in a loop and it creates a selection to save the data (tagged: Save Data, a dividing line and a Quit selection to stop the application. As I stated before, the tag for each item must be unique. To make meeting this requirement easy, I create hierarchical tags that are a colon delimited listing of the item’s parent tags. For example, the tag for the Quit selection on the File is File:Quit. This structure also makes the tag easy to parse in event handlers for the menu.

The Menu Event Handlers

Given the menu is itself a shared resource, the response to the menu events is also shared. Here is the menu event handler that is in the GUI. It handles the event that related to the application as a whole — Quit. As you would expect, all it does is run the VI that verifies that the user wants to quit before firing the standard Stop Application event.

quit menu handler

Likewise, there is the menu handler that resides in the acquisition processes. It simply calls the same data saving VI we used in the button press event handler.

save data menu handler

In both handlers, menu events for which they are not responsible, are handled by an (empty) default case.

Changing Resource Appearances

Remember the dummy VI we created earlier? Its job is to implement the requirement that the markings on the button and menu change to reflect the process that is managing them. Here is what it looks like:

modifying shared resource appearance

The My Name value is used to generate the new marking which is then applied to the button’s Boolean Text property and a node that uses it to set the menu item’s name. The node uses the item tag File:Save Data to identify the specific item it is changing. If you check out this node using the online help you’ll notice that it also let’s you enable and disable items, and add or remove check marks in front of items.

Code Testing

After making the required modifications to the other two data sources, we are ready to test the code. As you go from one data source to the next you’ll notice that the menu selection and button text change to reflect the name of the source that is being displayed. While you’re at it, test the data saving and see that the application remembers the last place that you saved a file.

This is all on subpanels for now. I have gotten some really good comments from several of you and will rolling some of those questions into future posts. In addition, when you download the code for a post, be sure to go through all of it. There are a lot of things going on in the code that I comment on in the VIs, but don’t have space for in the post.

Testbed Application — Release 10

Toolbox — Release 5

Oh yes, a preview… In the next post I will start looking at another popular design pattern and what a proper LabVIEW implementation of it looks like.

Until next time…

Mike…

Getting Everything Running

I left you last time stuck on the horns of a dilemma. To wit: It’s not very hard to create LabVIEW applications structured as multiple parallel processes that are for the most part operating independently of one another. However, now you are going to need some way to launch all those independent processes and manage their operation.

These are some of the issues that we’ll deal with this time, but first you may be wondering if this methodology is really worthwhile. Specifically, what benefits are to be garnered? In a word: modularity — on steroids (Ok, that’s three words. So sue me).

The Case for Autonomous Processes

A few posts ago, I dealt in broad terms with the issue of modularity and mentioned that effects both the design and implementation of an application. Consequently, modularity has implications that can reach far beyond simply the structure of an application. Modularity can also effect such diverse, and apparently unrelated, areas as resource allocation and even staffing.

For example, let’s say you have an application that needs to acquire data, display data, and manage system events that occur. Now let’s say you structure this application such that it has three loops on the same block diagram — or worse, one big loop that tries to do everything. How many developers can effectively work on the application at once? One.

Oh you might be able to split off a few random tasks like developing lower-level drivers, or prototyping the user interface, but when crunch time comes the work will fall to one person. Heaven help you if that one person gets sick. Or that one person gets hit by a bus. Or that one person gets tired of dealing with the stress caused by being the project critical path incarnate and quits.

And don’t forget that one developer is a best-case scenario. Such projects can easily turn into such a mess that there is no way anyone can “effectively” work on them. If you get thrust into such a situation, and you don’t have a manager that really and truly has your back, the best you can hope for is to survive the encounter. (And, yes. I am speaking from personal experience.)

But let’s say that you decide use a different modularization. Let’s say that you break the application into three independent, but interacting, processes. Now how many people can effectively work on the project at once? Three. Likewise, at crunch time how many people can assist with integration testing and validation? Three — and each one with a specific area of expertise in the project domain.

Oh, in case you’re wondering, “three” is a worst-case scenario. Depending how each of those three pieces are structured, the number of possible concurrent operations could go much higher. For instance, the lead developer of the DAQ module might decide to create separate processes for DAQ boards and GPIB instruments; or the GUI developer might identify 4 separate interface screens that will run independently, and so can be developed independently. Now you are up to 7 parallel development tasks, and 7 pairs of hands that can pitch in at crunch time.

So in terms of justification, ‘Nuff said… All we have to do now is figure out where to put the logic that we need.

Making a Splash [Screen]

Did you ever wonder why so many large applications have big splash screens telling you about the program you are launching? Is narcissism really running rampant in the software industry? Or is there a little slight-of-hand going on here?

Part of the answer to those questions lies in a magic number: 200. That number is important because that is the approximate number of milliseconds that average users will wait for a program to respond before they begin to wonder if something has gone horribly wrong. Any way you slice it 200-msec isn’t remotely long enough to get a large program loaded into memory and visible to the user.

So what is a developer to do? As quickly as possible put up an appealing bit of eye-candy the implicit (and occasionally explicit) purpose of which is to congratulate the user for having the wisdom and foresight to decide to launch your program. Then while the user is thus distracted, get everything else loaded and running as quickly as you can.

That is why programs have splash screens. It also points to one of the unique aspects of a splash screen: Unlike most VIs, what you see on the front panel of a splash screen often has little or nothing to do with what the VI is actually doing. Or put another way, splash screens are a practical implementation of the concept, “Ignore the man behind the curtain!”

Designing a Launch Pad

As you should expect from me by now, the first thing to do is consider the basic requirements for this launcher VI and list the essential components:

  1. A list of processes to be launched. As a minimum, this list will provide all the information needed to identify the process VIs. However it must also be expandable to allow the inclusion of additional runtime parameters.
  2. A loop to process the launch list. This loop will step through the launch list one element at a time and perform whatever operations are needed to get each process running. As a first-pass effort, the launcher must be able to handle reentrant and non-reentrant processes.

Because the loop that does the actual launching is pretty trivial, we’ll concentrate our design effort on a discussion of the data structure needed to represent the launch list. Clearly, the list will need to vary in size, so the basic structure will need to be an array. Next, to properly represent or describe each process to be launched (as well as any runtime data it may require) will probably require a variety of different datatypes, so the structure inside the array will need to be a cluster — and a typedef’d one at that. It is inevitable that eventually this data will need to change.

To determine what information the cluster will need to contain, let’s look at what we know about the call process that we will be using. Because these processes will be operating independently from one another, the launcher will use the Asynchronous Call-and-Forget method. To make this technique work, we will need the path to the VI so the launcher can load it into memory, and something to identify how each VI should be run. Remember, we are wanting to support both reentrant and non-reentrant processes. While the launch processes that the two types of VIs require are very similar they are not identical, so at the very least we need to be able to distinguish between them. But what should the datatype of this selector be? Most folks would figure that the selector only has 2 possible states, and so they would make it a Boolean…

…and most folks would be wrong.

There are 3 reasons why a Boolean value is incorrect:

  1. It is inherently confusing. There is no natural or intuitive mapping between possible logical values of this parameter and the true or false states available with a Boolean.
  2. It runs counter to the logical purpose of a Boolean. Boolean controls aren’t for just any value that has two states. They are for values that can only have two states. This selector coincidentally happens to have two states.
  3. It will complicate future expansion. There are other possible situations where the technique for using a given process might vary from the two currently being envisioned. When that happens you’ll have to go back and change the parameter’s fundamental datatype — or do something equally ugly.

The correct solution is, of course, to make the value a typedef enumeration with two values, “Normal” and “Reentrant”.

Handling Paths

While we are considering the data details, we also need to talk a bit about the VI path parameter. At first blush, this might seem a straight-forward matter — and in the development environment it is. The challenge arises when you decide to build your code into a standalone executable. To understand why this is so, we need to consider a little history.

With LabVIEW versions prior to LabVIEW 2009, executables that you created stored files internally in what was essentially a flat directory structure. Hence if you wanted to build a path to a VI inside an executable it was just the path to the executable with the VI name added to the end, like so:

C:\myProgram\myProgram.exe\myProgram.vi

This simple structure made it very easy to build a path to a VI and worked well for many years. However, as the LabVIEW development environment became more sophisticated, this simple structure began to exhibit several negative side-effects. One of most pernicious of those effects was one that nearly everyone tripped over at least once. The path of a VI in an executable, while simple to build, was different from the path to the same VI in the development environment.

To fix this problem (and many, many, many others) LabVIEW 2009 defined a new internal structure that more closely reflects the directory structure present in the development environment. Thanks to this change, once you know the path to the “project directory” inside the executable, the logic to building a path to a VI is exactly the same, regardless of the environment in which it was running. The only trick now is getting to that internal starting point, and that can be a bit tricky depending on how you have VIs stored on your computer. Being basically a simple man, when approached with a requirement such as this I prefer an uncomplicated approach — and what could be less complicated than a functional global variable?

Because the launcher VI is always in the project root directory, writing its path (stripped of the VI name, of course) to a FGV provides a fast shortcut for any process or function that needs to build an internal path. Note that this expedient is only needed for LabVIEW files that are located in the executable. For non-LabVIEW files, the Application Directory node provides the same logical starting point for path building.

Managing Windows

Finally, if you implemented an application with all the features that we have discussed to this point you would have an application that would acquire data in the producer loop, and seamlessly pass it to the consumer loop. Unfortunately, you wouldn’t be able to what it was doing because there wouldn’t be any windows open.

By default, when you dynamically call a VI the target of the call doesn’t automatically open its front panel. This behavior is fine for the acquisition VI, because we want it to run unseen in the background anyway. However, it also means that you can’t see the data display. To make the display visible we need to tweak a few VI properties for the display VI. To make this sort of setting easy, the Window Appearance portion in the VI properties dialog box provides a couple, predefined window definitions. The one that will get you what we want is the top-most radio button labeled Top-level application window. This selection sets a number of properties such as turning off the scrollbars and setting the VI to automatically open its front panel when it runs and closing it when it finishes.

Note that the Window Appearance screen also allows you to specify a runtime title for the window — an optional but professional touch to add to you application. This setting only defines a static title, you can also set it dynamically from the VI using a VI property node.

So that’s about it for now. The next time we get together I’ll introduce how I have applied all the infrastructure we have been discussing to the “testbed” application introduced in the post on UDEs.

Until next time…

Mike…