(For more resources related to this topic, see here.)
Working with a case structure
Case structure is equivalent to a conditional statement in a text-based programming language. We will create a few case structures that take different kinds of inputs, such as Boolean, numeric, string, enum, and error, to present different features of a case structure.
How to do it...
We will start with a Boolean case structure.
- The case structure in the following block diagram shows a case structure taking a Boolean input. It consists of False and True cases. The select node is also in the diagram to show that it can be used instead of a case structure when the input is Boolean. The select node will choose which input to output based on the Boolean input, similar to the case structure.
- The case structure in the following block diagram takes an integer as input. Keep in mind that when the input is a floating point value, it is converted into an integer. The ..-1 case will be executed when the input is less than or equal to 1. The 1, 2 case will be executed when the input is 1 or 2. The 3..5 case will be executed when the input value is between 3 and 5 inclusively. The 6.. case will be executed when the input is greater than or equal to 6. The 0, Default case will be executed when the input is 0 or does not meet the conditions of all the other cases, which is what Default means in this case.
- The following block diagram shows a case structure with a string input. The ''a''..''f'' case will be executed when the ASCII hex value of the input string is between a and f, including a, but excluding f. The ''f''..''j'' case will be executed when the ASCII hex value of the input string is between f and j, including f, but excluding j. If the input value does not meet the conditions of the previous states, the Default case will run.
- The following block diagram shows a case structure with enum input. These cases will be executed based on the input value. The Case 1 case is assigned as the default case. If the input does not meet the condition of Case 2 and Case 3, Case 1 will run by default. Enum is used for state machine, as it allows for self-documenting code. The value of an enum is also part of its type, so if we add a value in an enum type-def, the change will propagate to the rest of the block diagram.
- The following block diagram contains an error cluster input. It has two cases: No Error and Error. It is used extensively in a SubVI for bypassing input error, so that it doesn't get corrupted inside the SubVI.
How it works...
Case structure is the main way to make decisions in LabVIEW's code. It can take different types of input, such as Boolean, numeric, string, enum, and error cluster. For the Boolean case structure, sometimes it is more convenient to use the select node. It is important to note that the case structure should not be nested with too many layers and each case should be documented.
Working with an event structure
Event structure consists of one or more cases. Codes that are contained within a case are executed when a control event (mouse click, key stroke, and so on) or a user event (software-based event) occurs.
How to do it...
We will create an example that demonstrates using control event and user event for the event structure.
- The following example contains a numeric control (Input Num). When a number is entered, an event is triggered. For the Input Text string control, if a string is entered, an event is triggered, but no text will show up, as all the events (entering text) are discarded. When the Switch Boolean control is clicked, an event is triggered. If any event is triggered, the string indicator (Action) will update with a string that states what event has occurred. The following screenshot shows the front panel of the controls and indicator:
- The following screenshot shows the block diagram of the example. On the left, a Create User Event node is used to create a user event that can be generated within the code. The input user event data type is the data type used for data passing for a user event. The label of the data type in our example is Stop User, which will be used as the name of the user event. The while loop at the bottom iterates once every 500 ms, and it will generate a user event if the stop Boolean control is set to true. The event reference is registered with the Register for Events node and fed into the dynamic event terminal, which needs to be enabled by right-clicking on the frame of the event structure and then select Show Dynamic Event Terminals. In the top while loop, we see the event case that handles the event when the value of the Boolean changes for the Switch control. It is a good practice to put the control associated with the event case into the case, so that the control is easy to find and it is read by the program every time the event is triggered. When the Boolean value changes, the Action string indicator will update to show what event has occurred.
- The event case in the following screenshot will be executed when a key is pressed within the Input Num numeric control. The Action string indicator will update and show that the event has occurred.
- To create the previous event case, right-click on the event structure and select Add Event Case…. The following screenshot shows how to set up the case. Select the Input Num numeric control under Event Source and then choose which type of event to handle.
- The event case in the following screenshot will execute when a key is pressed within the string control, similar to the event case for the numeric control. However, notice ? behind the label of the Key Down event. This is a filter event which can discard the outcome of the event, contrary to all the previous event cases which use notify event. While our example runs as we enter values into the string control, we see that the key down event happened at the string control in the Action string indicator. The entered values do not appear in the string controls as the events are discarded.
Filter events give us the ability to trigger based on an event while discarding the event as though it never happened. Notify events will trigger based on an event without interfering with the occurrence of the event.
- The event case in the following screenshot will execute when a timeout event occurs. In this example, the timeout event will occur in 10000 ms, if no other events occur. We can change the timeout value as we wish. If we do not want the timeout event to trigger, we can wire a -1 to the timeout input.
- The event case in the following screenshot will execute when a user event is generated at the bottom while loop (refer to screenshot of the complete example). Recall that the name of the user event is the label of the data type when we created the user event. The user event is generated by the bottom loop when the stop Boolean control is set to true. This way both loops can stop each other's execution.
- If we have to create thirty event cases manually, it can be a lot of work. The following screenshot shows an example with thirty Boolean controls. For the example, we don't have to create thirty event cases for each Boolean control. The example gets all the references of the controls on the front panel as an array and registers all the references as a dynamic event. In this event case, if any of the Boolean controls has a value change event, the case will trigger. To get more resolution, we get the reference of the control for which the event originated from and print out a text.
How it works...
Whenever we find ourselves wanting to use a while loop to poll user for data, we should use the event structure instead. When the event structure is waiting for an event, it does not consume any CPU resources.
Working with loops
Loop is a common element in programming. In LabVIEW, there is for loop, while loop, and timed loop with features that facilitate LabVIEW programming. We will go over the for loop. For the while loop, its features are very similar to the for loop, so it is omitted.
How to do it...
The for loop is used when a predetermined number of iteration is needed. For an undetermined number of iteration, use the while loop instead.
- In the following screenshot, on the left, all the features of a for loop are shown; on the right is shown the result of the example. The input of the for loop is an array with elements 3 and 6. The entry point where the array enters the for loop is a  symbol, which means autoindexing. When the array is autoindexed, each iteration of the for loop will get an element of the array in order. Since the loop is autoindexed, the N symbol (number of iteration) at the upper-left hand corner does not need to be wired. The loop will iterate through each element of the array. In our case, the for loop will iterate two times. If multiple arrays with different lengths are wired into the for loop through autoindex, the number of times that the for loop will iterate is the size of the array with the least number of elements. The i would output the current iteration of the loop, and the stop symbol allows the program to stop the loop before completion. For enabling the conditional stop, right-click on for loop and enable the Conditional terminal.
- The example shows four output options. To select an option, right-click on the output terminal, select Tunnel Mode, and then select the desired option. For the last value option, the value at the very end of the array is outputted. For the Indexing option, the same number of elements as the input is outputted. For the Conditional option, we can create conditions for which elements are built into the output array. For the Concatenation option, we can concatenate to the end of a 1D array.
How it works...
The for loop iterates over the same code for a predetermined number of times. If the Conditional terminal is enabled, the for loop can be stopped prematurely. The for loop has many features, such as outputting the value of last iteration, indexing through an array (with and without a condition), and concatenating an array, that are useful for array processing.
Using the state machine architecture
State machine can transform a piece of sequential code into states with flexible transition between states. In a state machine, the code is self-documented and easy to read. In this section, we will use the state machine to program a simple rock-paper-scissors game simulator.
How to do it...
To start a state machine, it is a good idea to draw a flowchart first. Start by executing the following steps:
- To start, create a flowchart of the example program. See the following screenshot for the flowchart:
- Open a new VI and build a state machine, as shown in the following screenshot. Create an enum type-def with values such as Initialize, Wait for input, Timing, Computer's turn, and Shutdown. In a state machine, an enum is usually used, but a string is used frequently as well. Wait Until Next ms Multiple is used to slow down state transition. The state machine starts at the Initialize state, which will initialize indicators and shift registers. In this example, we are creating a state machine from scratch, but we can also utilize the state machine template built-in to LabVIEW. To use a template, create a VI by selecting File and New….
- The next state is Wait for input. It contains an event structure that waits for the user to click on the Start button, click on the Reset button, or close the panel. When the Start button is clicked on, a timer action engine that acts as a timer is started, as shown in the following screenshot:
- When the Reset button is clicked, all controls are reset to their default values:
- When the panel is closed, the action is discarded and the program is stopped, as shown in the following screenshot:
- The next state is the "Timing" state. If a user has decided a hand or when 3 seconds are up, the program transits into the next state. If not, the Timing state is revisited:
- The next state "Computer's turn" decides the computer's hand and updates the result. If the user selects a hand after three seconds, the computer's hand is determined randomly, as shown in the following screenshot:
- However, if the user selects a hand too early, the computer will determine what hand it needs to win the game and select that hand:
- Finally, the state machine goes back to the Wait for input state.
How it works...
For this program, after the user starts the program, the user would click on Start to begin the game. After the Start button is clicked on, the user has three seconds to select a hand or lose the game. If the user selects a hand too early, the computer determines the winning hand and selects it. If not, the computer's hand is determined randomly. After a game is completed, the user needs to click on Reset before clicking on Start for a new game.
In the Initialize state, local variables are used to set all controls to their default values. This is one of the few ways that are acceptable to use local variables. In LabVIEW, using local variables to pass data could be dangerous, since a race condition can occur to cause programs to behave erratically. However, to update user interface, local variables do come in handy. In the while loop level, each iteration is slowed down to 100 ms per iteration. If the state machine runs too fast, it can consume too much CPU resources.
In the Wait for input state, multiple actions are handled. If the Start button is clicked on, a timer is started. This is when the game begins.
After the program transits to the Timing state, the program will continue to loop back to it until the user decides a hand or until three seconds are up. The Boolean controls that represent the user's hands are built into an array and converted into a number, so that 1 represents Rock, 2 represents Paper, and 4 represents Scissors, based on binary math.
Next, the program transits into the Computer's turn state. The computer will decide a hand and output the result. When a game is done, the program goes back to Wait for input for another game.
Hopefully after reading this article you get a better understanding of how to work with case structures and event structures. Also you might have understood how to use the state machine architectures.
Resources for Article:
- DirectX graphics diagnostic [Article]
- Paths and curves in Raphael JS Vector Graphics [Article]
- Graphical Report Design with iReport: Part 2 [Article]