Helping a Window to Remember

One of the most common, most basic, and most mindless, things we do with computers every day is open windows. Launching a program or opening a document is often synonymous (on a practical level at least) with opening a window. As common as this action is, we rarely give any thought to what is going on behind the scenes when we open a window – hence the wisecrack about it being a mindless operation.

However, if we want to make the most of our design efforts, be need to replace this “mindlessness” with “mindfulness” by really thinking about the things that make windows easy and comfortable to use.

Defining a Well Behaved Window

As we begin looking at the behavior of windows, I want to emphasise that I am not talking about user interface design. User interface design deals with the details of what a window does functionally. Rather what I’m talking about is an examination to the behaviors a window should exhibit, regardless of what happens to be on the screen.

If we think about the window as a kind of frame that supports the interface’s core functionality, we see that one of the big things a window can do is remember things. Over the years, people have developed, and posted on the LabVIEW forums, a variety of toolboxes for storing generic window information like screen customizations, positions and settings. One of these toolsets combined with an event-driven structure can make it easy to significantly pump up the convenience factor of just about any application.

To see how these sorts of tools work, we’re going to enhance our undockable windows application with a simple addition that automatically saves a windows last position and restores that position the next time the window undocks. Although the basic logic is simple, it provides us with the opportunity to discuss many of the major issues that impact this sort of functionality.

The Data, and Where to Keep it

When considering the data that this sort of functionality requires and uses, the operative word is: “convenience”. By that I mean that this data may make using the screen more convenient, but nobody is going to be crying if it gets lost. In fact, a valuable behavior is the ability basically “reset” all the stored data back to its default value by simply deleting the data from the file that is storing it and letting the application rebuild it as needed.

Likewise the data should be of low “intelligence” value. In other words, we don’t want to include things in this data that could constitute a security risk. However, having said that, we also want to make sure that a well-meaning user doesn’t mess up the program’s operation by manually editing the data. My approach to blocking such edits has three major points:

  • Be careful about what you name things: You want to give identifiers that are, of course, meaningful. However, you don’t want to use names that will call attention to themselves in a way that says, “Hi, I’m a setting you might want to play with…”
  • Use a non-obvious data structure: For example, in our example we don’t save a window’s position as a simple list of four values. The problem is that a user looking at these values might decide to try to edit them manually – a simple act that could have some significant side effects. To see why consider that the way you move a window around the screen is by changing the VI’s WinBounds property. However, this property defines a windows position by essentially specifying the location of the window’s upper-left and lower-right corners. Consequently, while it does set the window’s location, it is also specifying the window’s size.
  • Provide a simple way to validate the data: Given that there is no way to know ahead of time what sort of data you might be wanting to store, validation might seem like a huge task, but it’s really not. Remember, when validating the data you don’t have to prove the data values are valid, just that they haven’t changed since the program wrote them.

As we get into how the position saving is implemented, you’ll see how I put these ideas into action, but first we need to look at how we are going to implement the capability from a high-level view.

Our Basic Approach

When adding in new or enhanced functionality, you want to do so in a way that requires as few modifications to (and has as little impact on) the existing structure, as possible. This ability to easily incorporate new functionality is a large part of the meaning of the term, “maintainable”. It is also why it is always good to think about your overall application in terms of functional blocks – or specific VIs that do specific things, and handle specific situations.

With that point in mind we know we have two basic operations we need to add: one sets the position when we open a VI and one writes a new position when we close it. Of these two operations, the simplest is the one that reads the last saved location and moves the window to that location. It’s simple because there is only one place in the code where that opening takes place, and that is right here:

Read Position Installed

This is the VI Float the VI.vi and if you compare it to the version that I presented last week you will note that it has one extra subVI that uses a reference to the VI being opened to look up and set the window position. we’ll look at exactly how it does that in just a moment. The operation that saves a VI’s last open position can also be boiled down to a single subVI, but due to the nature of our application, it will have to be installed in two locations.

Save Position Installed 1

Here’s the first of those locations. It occurs in the subVI Unfloat the VI.vi and it handles the case where the user closes any of the floating windows. Again you’ll notice one added subVI. Using the VI reference supplied to it, the subVI determines the target VI’s new window position and saves it. The other place where this VI occurs is in the event that stops the application.

Save Position Installed 2

Here the event logic checks to see if a window is docked, and if not calls the same subVI to save the window position of the VI associated with the reference.

Digging for Details

Now that we see where the modification fits into the application, let’s look at how the subVIs work – starting with the routine that saves the window position.

Save Window Location

As you can see, I am using the configuration file VIs to store the data in a text file using the INI file structure. However, it’s not the application’s INI file but rather one that I am creating in the user’s “My Documents” directory. This selection has at least a couple of implications. First it means that every user that logs into the computer will have their own set of customizations. Second, if the user wants to reset all their customizations back to default, all they have to do is delete or rename that one file.

Next, notice that this VI was designed to be usable in two different ways. If the VI reference input carries a valid reference the code uses that reference to get the data it wants to save. Alternatively, if the VI reference provided is not valid, the true case of the structure (not shown) open a reference to the VI calling this subVI and save the data for it.

Finally, let’s look at the subVI that the code uses to convert the window bounds data into the string that will be saved to the custom INI file.

Pack WinBounds

In keeping with the concepts I cited earlier, I obfuscate the datatype by flattening the structure to a string, convert the string into an array of U8s, and finally format the array as a string of 2-character hexadecimal values. However, before making that last conversion I provide a mechanism for ensuring data validity: I append a 16 bit CRC. The result is a string that will allow you to detect if it has been manipulated outside the program.

Turning now to the VI that retrieves the data, we see logic that reverses what was done in the position save routine. However, there is one added twist: if this VI is being called for the first time, the position of the target VI might not be in the INI file. Consequently the code needs to be able to recognize that situation and just let the windows open in its default position.

Read Location and Position Window

The subVI (below) that converts the string from the INI file back into the LabVIEW data structure for defining a windows bounds, generates a structure containing all 0s when it is passed an empty string – which is what you get when you try to read a string value from an INI file that doesn’t exist.

Unpack WinBounds

Also notice how this VI verifies the CRC. It’s commonly believed that in order to verify a CRC you have to split the CRC from the message, calculate a new CRC on the message and compare the result to the CRC received as part of the message. However, such is not the case. Due to the way the CRC calculation works, if you simply perform a CRC on the entire message including the original CRC the results will always be 0 for a valid message and CRC. Hence, the logic only goes to the trouble of splitting the message from the CRC after it has determined that the message is valid. In the case where the second CRC calculation is not zero (indicating a corrupted message) the logic outputs the same invalid data structure that you get from a null input string.

Given these facts, the VI for reading the target VI’s last position only has to look for that known-invalid data structure and if it finds it, bypasses the logic that set the window’s bounds.

Undockable Windows – Release 2
Toolbox – Release 10

The Big Tease

So there we have it, a basic framework that you can use to implement a variety of “window memory” functions. But what about next time? I have talked a lot about processes that run in the background. What happens though, if you want to be able to provide a minimal interface that isn’t always there but can be easily called up when needed. Next time I’m going how you can utilize the Windows system tray to house just such an interface. At the same time we’ll look at one of the more interesting backwaters of LabVIEW development – .net callbacks.

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…

Building a Web Backend in LabVIEW

When building a web-based application, one of the central goals is often to maximize return on investment (ROI) by creating an interface that is truly cross-platform. One of the consequences of this approach is that if you are using a LabVIEW-based program to do so-called “backend” tasks like data acquisition and hardware control, the interface to that program will likely be hidden from the user. You see the thing is, people like consistent user interfaces and while LabVIEW front panels can do a pretty good job as a conventional application, put that same front panel in a web page and it sticks out like the proverbial sore thumb.

Plus simply embedding a LabVIEW front panel in a web pages breaks one of the basic tenets of good web design by blurring the distinction between content and appearance. Moreover, it makes you — the LabVIEW developer — at least partially responsible for the appearance of a website. Trust me, that is a situation nobody likes. You are angered by what you see as a seemingly endless stream of requests for what to you are “pointless” interface tweaks, “So big deal! The control is 3 pixels too far to the left, what difference does that make?” And for their part, the full-time web developers are rankled by what they experience as a lack of control over an application for which they are ultimately responsible.

If you think about it, though, this situation is just another example of why basic computer science concepts like “low coupling” are, well, basic computer science concepts. Distinguishing between data collection and data presentation is just another form of modularity, and we all agree that modularity is A Very Good Thing, right?

It’s All About the (Data)Base

So if the concept that is really in play here is modularity, then our immediate concern needs to be the structure of the interface between that part of the system which is our backend responsibility, and that which is the “web guy’s” customer facing web-based GUI.

Recalling what we have learned about the overall structure of a web application, we know that the basic way most websites work is that PHP (or some other server-side programming tool) dynamically builds the web pages that people see based on data that they extract from a database. Consequently, as LabVIEW developer trying to make data available to the web, the basic question then is really, “How do I get my data into their database?”

The first option is to approach communications with the website’s database as we would with any other database. Although we have already talked at length about how to access databases in general, there is a problem. While most website admins are wonderful people who will share with you many, many things — direct access to their database is usually not one of those things.

The problem is security. Opening access to your LabVIEW program would create a security hole through which someone not as kind and wholesome as you, could wiggle. The solution is to let the web server mediate the data transfer — and provide the security. To explore this technique, we will consider two simple examples: one that inserts data and one that performs a query. In both cases, I will present a LabVIEW VI, and some simple PHP code that it will be accessing.

However, remember that the point of this lesson is the LabVIEW side of the operations. The PHP I present simply exists so you can get a general idea of how the overall process works. I make no claims that the PHP code bears any similarity to code running on your server, or even that it’s very good. In fact, the server you access might not even use PHP, substituting instead some other server-side tool such as Perl. But regardless of what happens on the other end of the wire, the LabVIEW code doesn’t need to change.

As a quick aside, if you don’t have a friendly HTTP server handy and you want to try some of this stuff out, there is a good option available. An organization called Apache Friends produces an all-in-one package that will install a serviceable server on just about any Windows, Linux or Apple computer you may have sitting around not being used. Note that you do not want to actually put a server that you create in this way on the internet. This package is intended for training and experimentation so they give short shrift to things like security.

The following two examples will be working with a simple database table with the following definition:

CREATE TABLE temp_reading (
   sample_dttm  TIMESTAMP PRIMARY KEY,
   temperature  FLOAT
   )
;

Note that although the table has two columns we will only be interacting directly with the temperature column. The sample_dttm column is configured in the DBMS such that if you don’t provide a value, the server will automatically generate one for the current time. I wanted to highlight this feature because the handling of date/time values is one of the most un-standardized parts of the SQL standard. So it will simplify your life considerably if you can get the DBMS to handle the inserting or updating of time data for you.

Writing to the Database

The first (and often the most common) thing a backend application has to do is insert data into the database, but to do that you need to be able to send data to the server along with the URL you are wanting to access. Now HTTP’s GET method which we played with a bit last week can pass parameters, but it has a couple big limitations: First, is the matter of security.

The way the GET method passes data is by appending it to the URL it is getting. For example, say you have a web page that is expecting two numeric parameters called “x” and “y”. The URL sent to the server would be in the form of:

http://www.mysite.html?x=3.14;y=1953

Consequently the data is visible to even the most casual observer. Ironically though, the biggest issue is not the values that are being sent. The biggest security hole is that it exposes the names of the variables that make the page work. If a person with nefarious intent know the names of the variables, they can potentially discover a lot about how the website works by simply passing different values and seeing how the page responds.

A second problem with the GET method’s way of passing data is that it limits the amount of data you can sent. According to the underlying internet standards, URLs are limited to a maximum of 2048 characters.

To deal with both of these issues, the HTTP protocol defines a method called POST that works much like GET, but without exposing the internal operation or limiting the size of the data it can pass. Here is an example of a simple LabVIEW VI for writing a temperature reading to the database.

Insert to database with PHP

This code is pretty similar to the other HTTP client functions that we have looked at before, but there are a few differences. To begin with, it is using the POST we just talked about. Next, it is formatting and passing a parameter to the method. Likewise, after the HTTP call it verifies that the text returned to it is the success message. But where do those values (the parameter name and the success message) come from? As it so happens I didn’t just pull them out of thin air.

Check out the URL the code is calling and you’ll note that it is not a web page, but PHP file. In fact, what we are doing is asking the server to run a short PHP program for us. And here is the program:

<?php
	if($dbc = mysqli_connect("localhost","myUserID","myPassword","myDatabase")) {
    	// Check connection
		if (mysqli_connect_errno()) {
			// There was a connection error, so bail with the error data
			echo "Failed to connect to MySQL: " . mysqli_connect_error();
		} else {
			// Create the command string...
			$insert = "INSERT INTO temp_reading (temperature) VALUES (" . $_POST["tempData"] . ")" ;
			
			// Execute the insert
			if(!mysqli_query($dbc,$insert)){
				// The insert generated an error so bail with the error data
				die('SQL Error: ' . mysqli_error($dbc));
			}
			
			// Close the connection and return the success message
			mysqli_close($dbc);
			echo "1 Record Added";
		}
	}
?>

Now the first thing that you need to know about PHP code is that whenever you see the keyword echo being used, some text is being sent back to the client that is calling the PHP. The first thing this little program does it try to connect to the database. If the connection fails the code echoes back to the clients a message indicating that fact, and telling it why the connection failed.

If the connection is successful, the code next assembles a generic SQL statement to insert a new temperature into the database. Note in particular the phrase $_POST["tempData"]. This statement tells the PHP engine to look through the data that the HTTP method provided and insert into the string it’s building the value associated with the parameter named tempData. This is where we get the name of the parameter we have to use to communicate the new temperature value. Finally, the code executes the insert that it assembled and echoes back to the client either an error, or a success message.

Although this code would work “as is” in many situations, it does have one very large problem. There is an extra communications layer in the process that can hide or create errors. Consider that a good response tells you that the process definitely worked. Likewise receiving one of the PHP generated errors tells you that the process definitely did not work. A network error, however, is ambiguous. You don’t know if the process failed because the transmission to the server was interrupted; or if the process worked but you don’t know about it because the response from the server to you got trashed.

PHP Mediated Database Reads

The other thing that backend applications have to do is fetch information (often configuration data) from the database. To demonstrate the process go back to the GET method:

Fetch from database with PHP

As with the first example, the target URL is for a small PHP program, but this time the goal is to read a time ordered list of all the saved temperatures and return them to the client. However, the data needs to be returned in such a way that it will be readable from any client — not just one written in LabVIEW. In the web development world the first and most common standard, is to return datasets like this in an XML string. This standard is very complete and rigorous. Unfortunately, it tends to produce strings that are very large compared to the data payload they are carrying.

Due to the size of XML output, and the complexity of parsing it, a new standard is gaining traction. Called JSON, for JavaScript Object Notation, this standard is really just the way that the JavaScript programming language defines complex data structures. It is also easy for human beings to read and understand, and unlike XML, features a terseness that makes it very easy to generate and parse.

Although, there are standard libraries for generating JSON, I have chosen in this PHP program to generate the string myself:

<?php
    if($dbc = mysqli_connect("localhost","myUserID","myPassword","myDatabase")) {

    	// Check connection
		if (mysqli_connect_errno()) {
			echo "Failed to connect to MySQL: " . mysqli_connect_error();
		} else {
			// Clear the output string and build the query
			$json_string = "";
			$query = "SELECT temperature FROM temp_reading ORDER BY sample_dttm ASC";
			
			// Execute the query and store the resulting data set in a variable (called $result)
			$result = mysqli_query($dbc,$query);
			
			// Parse the rows in $result and insert the values into a JSON string
			while($row = mysqli_fetch_array($result)) {
				$json_string = $json_string . $row['temperature'] . ",";
			}
			
			// Replace the last comma with the closing square bracket and send the
			// to the waiting client
			$json_string = "[" . substr_replace($json_string, "]", -1);
			echo $json_string;
		}
	}
	mysqli_close($dbc);
?>

As in the first PHP program, the code starts by opening a database connection and defining a small chunk of SQL — this time a query. The resulting recordset is inserted into a data structure that the code can access on a row by row basis. A while loop processes this data structure, appending the data into a comma-delimited list enclosed in square brackets, which the JSON notation for an array. This string is echoed to the client where a built-in LabVIEW function turns it into a 1D array of floats.

This technique works equally well for most complex datatypes so you should keep it in mind even if you are not working on web project. I once had an application where the client wanted to write the GUI in (God help them) C# but do all the DAQ and control in LabVIEW-generated DLLs. In this situation the C# developer had a variety of structs containing configuration data that he wanted to send me. He, likewise, wanted to receive data from me in another struct. The easy solution was to use JSON. He had a standard library that would turn his structs into JSON strings, and LabVIEW would turn those strings directly into LabVIEW clusters. Then on the return trip my LabVIEW data structure (a cluster containing a couple of arrays) could be turned, via JSON, directly into a C# struct. Very, very cool.

The Big Tease

So what is in store for next time? Well something I have been noticing is that people seem to be looking for new ways to let users interact with their applications. With that in mind I thought I might take some time to look at some nonstandard user interfaces.

For my first foray into this area I was thinking about a user interface where there are several screens showing different data, but by clicking a button you can pop the current screen out into a floating window. Of course, when you close the floating window, it will go back into being a screen the you can display in the main GUI. Should be fun.

Until Next Time…

Mike…

Understanding Web I/O

A question that seems to be popping up with increased urgency is how to incorporate LabVIEW into an environment that is largely web-based. As you would expect, in a technology that is developing as fast as the web, it can be hard to keep track of where things are right now. In fact at least one major tech publisher (O’Reilly Media) is diving full throttle into electronic publishing because with the lead time inherent in conventional publishing, web development books tend to be out of date before they can even be printed.

This is important to us because we don’t have the time or money to waste on technological dead ends. For example, I wouldn’t recommend you buy stock in companies manufacturing compact fluorescent lightbulbs. I mean who really wants to have to call in a hazmat team to clean up the mercury contamination when one breaks? The “curly light bulb” may be all the rage right now, but it is a technological dead end — to be replaced by LEDs. In the same way, I believe that many of the technologies that are in use today to access online resources are also technological dead ends.

If your company is online right now or wants to offer some service online, the standard way of doing that is with an “app”. Or rather, I should say, several apps. You will need an app for Android, one iOS, one for Windows Mobile, and perhaps others as well. But to get them you will need separate at least three separate development team because none of those operating systems are compatible with one another — or for that matter even very similar. This approach is simply not sustainable, and is another technological dead end. The solution is to build a system based on the platform independent standards that drive the web. So we need to learn where LabVIEW fits into this picture.

The Web Landscape

The first thing to understand is that the web as a collection of static HTML pages is gone. The web of today is a dynamic environment where the web pages you view (including this one) are built on the fly and in some cases may only exist for the few milliseconds it takes for the server to transmit it to you. While the underlying technology that accomplishes this magic is fascinating, the good news is that we don’t really need to know very much about it to accomplish our goals. Instead it is adequate for our purpose to know who the “main players” are from our (rather limited) point of view and how they interact.

One of the key developments in the past few years has been the understanding that each piece of the overall web environment needs to have a clearly defined role and that the various components don’t step outside their designated roles. To see what I mean, let’s consider a few of the basic pieces that you will encounter working with LabVIEW:

HTML — The Content

Tn the beginning the need was simple, Researchers at CERN needed a way to use this new “internet” to share research results with colleagues. But they wanted more than just a way to ship text file around. They wanted documents that could include pictures and graph, and could be linked to one another. In short, they wanted (to borrow a buzzword from an even earlier time) hyper-text.

The approach that they used to reach for this goal was simple: take bare text documents and embed in them tags (which were also text) that could tell a custom designed program called a “browser” how to treat the text contained in the tags. The thing to remember is that this idea was hardly a new one — so-called “markup languages” had been used for decades in the mainframe environment to implement word processors and report generators.

Even today, HTML (hyper text markup language) documents are just text files with embedded tags. This point is an important one to remember because it means that while browsers have one way of interpreting tags, other programs — even LabVIEW, or programs you write in LabVIEW — can read the same files and parse them to extract the data, the same as they would any other text file.

CSS — How Things Should Look

As it was originally created, HTML mushed together a lot of different things. Some tags defined the structure of the document, some were links and some simply defined what the text should look like. But this approach soon began to present some limitations. For example, if the logic defining what a particular bit of text looks like is embedded in the document, everybody has to see the same thing no matter how big their browser window might be or what the physical characteristics of their screen might be.

The solution to this problem with as easy. All you had to do is define a separate syntax for defining the content’s appearance, and then take all that logic and move it to a separate file with a .css file extension called a style-sheet. Now two people could view the same HTML document and would see it formatted to best fit their system because their browsers were using style sheets that were optimized for their system hardware.

As a practical example of this flexibility in action, consider the very webpage you are reading right now. Regardless of whether you are looking at it on a monitor on your desk, or a smartphone in the palm of your hand, everybody gets to see a nicely styled layout that fits their device — and I only had to generate the content once.

PHP — Server-Side Programmability

But even with that styling flexibility, there is still a very large problem. If all you have at your disposal is HTML, then each web page becomes a separate program that somebody has to write. Imagine if you will how much effort it would take to maintain a site such as Amazon if every on of its thousands of products needed its own handcrafted and programmed web page. The solution is to automate the creation of web pages using a programming language that can automatically assemble pages from predefined common components as they are needed.

One of the most popular language for this kind of work is PHP — though there are many others. It works by inserting itself into the HTML process in one of two ways. First, there are special HTML tags that cause the server to momentarily stop sending the data from the HTML file and run a PHP function. The purpose of this function would be to programmatically build and echo to the waiting browser some portion of the page, like a standardized menu structure or footer.

The second way PHP may appear is that some web servers (like Apache, for instance) will automatically call a predefined file called index.php if you access the site without specifying a specific page. Consequently, while it might look to you like you are accessing a webpage, you are really running a PHP program that builds the initial screen that you see on the fly. In addition, if you watch your URL bar while browsing you will occasionally notice that you are accessing pages with the same php file extension.

Database — Data Storage

If you have PHP building web pages dynamically, a logical question to ask is where it gets the data that it uses to build the dynamic pages that we see in our browsers? Not surprisingly, PHP uses a database, and it does so for the same reason that we use databases when building a test application: because it’s better to reconfigure than it is to recode. In fact, one of the major functions of PHP programs is to query a local database and pass the result to the browser for display. You will also find PHP programs storing to a database the information that you provide when filling out forms to do things like ordering pizza online or registering for a blog.

The type of databases that are used can vary widely though the most common is MySQL. The important thing to remember is that the specific database that is used to fill this particular niche in the overall web ecosystem is largely irrelevant.

Getting back to LabVIEW

Now that we understand how some of the major pieces fit together, we can begin to explore how our LabVIEW programs fit into this picture. Since the point of all this structure is to manage test files being sent to browsers, it shouldn’t be too much of a surprise to learn that one of the major ways that LabVIEW programs fit in is by pretending to be browsers. In support of that “deception” LabVIEW comes with a set of HTTP client VIs that support all the major HTTP methods as well as routines for dealing with access control, and setting session parameters that you are wanting to use. As an example of how the interface works, I have created a VI which illustrates about the simplest transaction possible:

simple get method

The code starts by opening an HTTP session, It then uses the VI that implements the HTTP GET method to fetch a URL and display the contents in a string indicator. Finally, it closes the connection. As you will see, the tricky part of this operation isn’t so much how you do it, but rather what do you do with the data you get back. For example, if you run this VI with the default value in the url control you get something that looks like this:

raw web results

Now you have to admit that the data in the Response indicator would seem to fit the definition that most people have for “unintelligible garbage”. But wait a minute, look at the first 6 bytes of the file. Many proprietary file formats will put a short identifier in the first few bytes of the file. For example, if you look at a Zip archive, the first three characters are “ZIP”. Applying this understanding to the data we just read from the internet, “GIF89a” is how files are identified that meet the 1989 Graphics Interchange Format standard. In other words, it’s a gif format graphic. To see the image all you have to do it provide a way to save the data to a file by adding a bit of logic to the block diagram.

gif saver

You see the url is the link that the LabVIEW forum uses to fetch one of the predefined avatars, in this case one called “fatbot”. But there are more serious things that you can do also. For example, by parsing the HTML that you get back from reading an actual webpage, you can obtain data that you might not otherwise be able to access. However, if you plan to do such data harvesting, be sure that you have the permission to do so. Otherwise the practice could lead to serious ethical/karmic/legal issues.

So why would someone need to do this sort of data collection as part of a professional test system? One possible scenario would be that the application you are needing to test is inaccessible, and all you can see is the data that it publishes online. Or perhaps, the web interface is the thing that you are wanting to test.

The big risk, of course, is that if you don’t have control over the page that you’re accessing, you can have your code suddenly stop working because the owner changed their webpage. Ideally, you should be able to negotiate changes with the site owner, but if not you need to remember that your number 1 mitigation strategy is good design. While you might not be able to keep changes from breaking your code, you can at least limit the damage to perhaps 1 or 2 VIs.

Assuming that you can negotiate with the folks that are working on the webpage, one of the things that you can request is that they surround the data that you need with special tags like so: (Imagine this is in the middle of a block of text on the web page)

… the test was performed by <lvData id="testOp">John Doe</lvData> using test fixture <lvData id="testLoc">5</lvData> …

This snippet defines a unique HTML tag lvData that allows the LabVIEW code that is parsing the content to quickly find the values it want, while the id="…" clauses allow the LabVIEW application identify the label to associate with each value. Moreover this creation of an ad hoc tag won’t impact the viewing of the page with a standard browser because fundamental to the operation of all browsers is the simple rule: If you see a tag you don’t recognize, ignore it. Here is code that you could use to locate and parse these tags.

parse lvData

This idea could also be expanded by embedding the custom tags in HTML comments. Like this:

<!-- <lvData id="testOp">John Doe</lvData> <lvData id="testLoc">5</lvData> -->

In this implementation, the comment tag would hide the custom tags from view when the page is being displayed in a browser, but they would still be available to a LabVIEW application parsing the page as text. Using this technique you could hide data inside any page — perhaps even this one.

The Big Tease

This should be enough for now. Next time we’ll look at how to use LabVIEW as a data source for a web-based application. We’ll check out the HTTP POST method, and even look at a little PHP code and some JSON data.

Until Next Time…

Mike…