Step reference

This section provides a reference for steps used in background programs.

# - comment

A comment is just that, and is there to clarify things for the user.

Figure 12‑80. Comment.


ASSIGN creates a local variable for your program, which you name in the Name field. There are numerous options:

Value or expression

The Value entry is evaluated with the Python eval() statement, and the result assigned to the variable specified in Name entry. The result of the eval() determines the Python type (str, float, int, list, etc.) of your variable. Values assigned to an expression have 5 interface options for appearing in DIALOG.

Figure 12‑81. ASSIGN to an expression. See Grid items for more details.

Data Dictionary value

A local variable can be assigned to anything that can be found in the Data Dictionary (Figure 12‑82). The assignment can be a 'snap shot' (capture the value, and keep it) or tracked (variable continually updated automatically).

Figure 12‑82. ASSIGN to a Data Dictionary value.

Status Dictionary value

A local variable can be assigned to anything that can be found in the Status Dictionary (Figure 12‑83). The assignment can be a 'snap shot' (capture the value, and keep it) or tracked (variable continually updated automatically).

Figure 12‑83. Status.

(Advanced) Topic and Key

The Topic and Key option provides a general purpose method to get to almost any item (or groups of items), even if they are not in the Data or Status Dictionaries. Most values of interest have a topic and name (key). Every item in the Data Dictionary also has a group and label. The system's Data Dictionary shows group, label, name, and topic (Figure 12‑84).

  • Topic: the topic under which this item is published in internal LI-6800 communications. Except for its appearance in the Data Dictionary, topic is otherwise hidden from the user interface.
  • Name: the unique (for that topic) identifier for this item.
  • Group: A collection of items.
  • Label: Often the same as Name, but can be different.

Group and Label are often used as identifiers (Figure 12‑84).

Figure 12‑84. Group and label show up several places (and in different order) in the interface, including grids, graphs, and the stability screen.
Figure 12‑85. Name, Group, and Topic.

In Figure 12‑85, we are looking at the entry for Qamb_out, but that is just it’s screen label. It’s real name is PPFD_out, and it can be gotten via the topic (licor/li6850/output/DATA), or the group (Meas).

Figure 12‑86 shows how to use ASSIGN [Topic and Key] to access the entire collection of items in group Meas:

Figure 12‑86. Leaving the ‘Key’ black returns a dictionary of everything in the Group or Topic.

What can you do with this? Here is an example: the program /home/licor/apps/examples/ illustrates how to log everything in the Meas group to a comma separated file, with elapsed time, as fast as new data sets are available.

Figure 12‑87. Logging the Meas group, with elapsed time.

The output of this program is shown in Listing 12‑3.

Listing 12‑3. Listing of /home/licor/logs/meas values.txt.

Elapsed , 'CO2_r', 'CO2_s', 'Fan_speed', 'Flow', 'H2O_r', 'H2O_s', 'Offset', 'Offset2', 'PPFD_in', 'PPFD_out', 'Pchamber', 'Press', 'TIME', 'Tchamber', 'Tleaf', 'Tleaf2'

0.044217 , 162.356, 164.168, 0, 600.006, 4.26871, 4.24712, 0, 0, 0.811979, 11.1801, -0.00557787, 97.3788, 1549397993.6, 26.6202, 21.6749, 997.995

0.276225 , 162.335, 164.184, 0, 599.989, 4.26887, 4.247, 0, 0, 0.819595, 11.1801, -0.00569272, 97.3789, 1549397994.1, 26.6191, 21.686, 997.981

0.788974 , 162.331, 164.182, 0, 599.983, 4.26883, 4.24701, 0, 0, 0.830257, 11.1801, -0.00573881, 97.3794, 1549397994.6, 26.6181, 21.7068, 997.96

1.219423 , 162.33, 164.191, 0, 599.989, 4.26866, 4.24707, 0, 0, 0.853101, 11.1801, -0.00577292, 97.3796, 1549397995.1, 26.6173, 21.7342, 997.934

1.85875 , 162.337, 164.201, 0, 600.013, 4.26838, 4.24726, 0, 0, 0.869853, 11.1801, -0.00571798, 97.3801, 1549397995.6, 26.6169, 21.7587, 997.926

2.278488 , 162.359, 164.205, 0, 600.005, 4.26831, 4.24704, 0, 0, 0.86224, 11.1801, -0.0057185, 97.3801, 1549397996.1, 26.6169, 21.7815, 997.928

2.801033 , 162.367, 164.202, 0, 600.037, 4.26825, 4.24704, 0, 0, 0.854626, 11.1801, -0.00566928, 97.3802, 1549397996.6, 26.6169, 21.795, 997.928

3.281008 , 162.386, 164.218, 0, 600.009, 4.2684, 4.24721, 0, 0, 0.847013, 11.1801, -0.00566537, 97.3798, 1549397997.1, 26.6169, 21.8024, 997.926

3.809381 , 162.402, 164.22, 0, 600.015, 4.26823, 4.24701, 0, 0, 0.837876, 11.1801, -0.00561485, 97.3793, 1549397997.6, 26.6169, 21.7904, 997.924

4.261619 , 162.42, 164.214, 0, 600.008, 4.26816, 4.2471, 0, 0, 0.822646, 11.1801, -0.0055487, 97.3793, 1549397998.1, 26.6169, 21.7655, 997.922

4.794935 , 162.444, 164.221, 0, 600.03, 4.2682, 4.24693, 0, 0, 0.810461, 11.1801, -0.00549713, 97.3787, 1549397998.6, 26.6164, 21.7421, 997.929

5.244639 , 162.491, 164.239, 0, 600.011, 4.26834, 4.24663, 0, 0, 0.810461, 11.1801, -0.00545026, 97.3785, 1549397999.1, 26.6156, 21.7197, 997.943

5.888604 , 162.547, 164.228, 0, 600.003, 4.26827, 4.24641, 0, 0, 0.807415, 11.1801, -0.00548854, 97.3784, 1549397999.6, 26.6146, 21.6891, 997.945

6.246275 , 162.608, 164.239, 0, 599.998, 4.26845, 4.24642, 0, 0, 0.792185, 11.1801, -0.00545416, 97.3788, 1549398000.1, 26.6135, 21.6532, 997.938

6.887768 , 162.666, 164.233, 0, 599.985, 4.26856, 4.24679, 0, 0, 0.778478, 11.1801, -0.00550391, 97.3785, 1549398000.6, 26.6125, 21.6257, 997.939

7.343789 , 162.712, 164.229, 0, 600.01, 4.26845, 4.24664, 0, 0, 0.770865, 11.1801, -0.0055724, 97.3789, 1549398001.1, 26.6117, 21.6039, 997.946

7.768044 , 162.746, 164.234, 0, 600.008, 4.2684, 4.24698, 0, 0, 0.766297, 11.1801, -0.00558334, 97.3792, 1549398001.6, 26.6112, 21.5872, 997.95

8.230504 , 162.761, 164.235, 0, 599.988, 4.26836, 4.24708, 0, 0, 0.77391, 11.1801, -0.00564896, 97.3795, 1549398002.1, 26.6109, 21.574, 997.953

8.756039 , 162.752, 164.235, 0, 599.962, 4.26828, 4.24725, 0, 0, 0.780001, 11.1801, -0.00570001, 97.38, 1549398002.6, 26.6111, 21.5457, 997.95

9.268605 , 162.711, 164.223, 0, 599.997, 4.26825, 4.24755, 0, 0, 0.780001, 11.1801, -0.00577735, 97.3802, 1549398003.1, 26.6117, 21.5073, 997.944

9.797924 , 162.667, 164.235, 0, 600, 4.26832, 4.24757, 0, 0, 0.781524, 11.1801, -0.00581069, 97.3799, 1549398003.6, 26.6126, 21.4895, 997.945

(Advanced) XML value

There are a number of "lower-level" values that come from communication with the actual hardware devices (console, head, fluorometer). Many of these are repackaged and available through the Data or Status Dictionaries, but not everything. To access (get and set) these, it is necessary to use an XML interface.

Figure 12‑88. Assigning a value using xml.

This XML entry licor/li6850/cfg/pump/speed is a shorthand for selecting the XML value at



AUTOENV provides a means for a BP to configure and control any of the six Auto Controls. There are four sub-options ('Actions') for an AUTOENV step, and are illustrated in the figures below.

A BP can configure and start an AutoEnv, but note that once running, the AutoEnv is independent of the BP that started it; it will keep running when the BP ends, unless the BP stops it or the AutoEnv hits an end with AutoRepeat off.

With Action set to Define (Figure 12‑89), you can configure everything relating to the Y-axis.

Figure 12‑89. How the controls of AUTOENV [Define] map to the user interface.

With Action set to Set time & direction (Figure 12‑90), you can set direction and location on the time axis.

Figure 12‑90. The AUTOENV [Set time & direction] controls set the direction and location (time).

With Action set to Start or Stop (Figure 12‑91), you can turn the AutoEnv on or off.

Figure 12‑91. AUTOENV [Start] and [Stop].

Figure 12‑92 illustrates the use of AUTOENV.

Figure 12‑92. Running the AUTOENV test program.

Note that there is nothing in the AUTOENV user interface that actually captures the current state of any AutoEnv; it is write-only, basically. You can, however, get a dictionary of AutoEnv configuration information via ASSIGN[Topic and Key], using the topic licor/li6850/scripts/autoenv/x/constants where x is 1, 2, ... 6.


BREAK provides a way to exit from a LOOP or WHILE (Figure 12‑93).

Figure 12‑93. Using BREAK to exit a LOOP.


DEFINE is the BP equivalent of a subroutine or function. It defines a collection of program steps that can be called from anywhere (CALL), and have parameters passed to it.

Variable scope

User defined variables are local to the main program, or to the DEFINE function in which they are created (see EXEC for a method to make variables that are global in scope).

Figure 12‑94. Illustration of the local scope of BP variables.

Passing by value or reference

Part of designing a DEFINE is specifying for each argument whether it is passed by value or reference.

Normally you pass by value, which means it is the value of the argument in the CALL statement that is important. You can use an expression or variable for that argument in the calling statement (e.g., CALL Something(x1, x2/16.2)).

Passing by reference forces you to use a variable name, and any changes to the value of that variable are "passed back" to the calling context. Figure 12‑95 illustrates. The DEFINE PassByTest takes two arguments, val is pass-by-value, ref is pass-by-reference. The function doubles both values that are passed in. In the calling context, this does not affect the pass-by-value variable a, but does affect b, which gets the final value of ref.

Figure 12‑95. Comparison of pass-by-value and pass-by-reference.

Thus, passing by reference is typically the method to use if you want to get some information back from a DEFINE, rather than just pass information to it.


DIALOG displays a dialog box for obtaining input from the user (Figure 12‑96)

Figure 12‑96. The parts of a BP dialog, and how they are configured in a DIALOG step.

The DIALOG's setup interface (Figure 12‑96 bottom) allows you to specify the dialog's parameters:

  • Title should be a string, or string variable name. The system always appends "(BP#n)" to the title, where n is the BP's pid number.
  • Subtitle should be a string or a string variable name.
  • Text box (optional) should be a string or string variable. To force line breaks, embed a nn (backslash n) in the string.
  • Grid items (optional) is a list of variables whose values can be edited in the dialog.
  • Buttons is a list of button labels. In no list is specified, an "OK" button will be provided.
  • Button result name. The BP variable that will contain the label of the button the user taps (closing the dialog). The DIALOG step will create this variable if it doesn't already exist.

While the dialog is displayed, the BP is in a wait state until the user presses one of the dialog's buttons.

Grid items

Grid items are items with a user interface, and can be added to a dialog by including one or more variable names in the Grid items list of the DIALOG's configuration. Each name is used to access the current value of the variable, and the Dialog interface information that was in the ASSIGN or TABLE setup for that variable.

A Checkbox (Figure 12‑97) is an appropriate interface for a variable that can have a True or False value. The item label tells how the check box is to be labeled.

Figure 12‑97. Check box.

A Dropdown list (Figure 12‑98) is appropriate for letting the user select from a scrollable list.

Figure 12‑98. Dropdown list.

An Editbox (Figure 12‑99) is suitable for strings or values. There is also a checked option.

Figure 12‑99. Edit boxes can be checked or unchecked.

The Radio buttons option (Figure 12‑100) is appropriate for letting the user select from a small selection. If your label and list of items is too long, it will not all be visible in the dialog box.

Figure 12‑100. Radio buttons list.

The Text dialog option (Figure 12‑101) is not editable, but is useful for showing the current value. This is the only dialog option available for all ASSIGN items.

Figure 12‑101. The text option shows current value.

The Table and Text summary dialog options (Figure 12‑102) are available for variables assigned to the TABLE; one is editable, one is not.

Figure 12‑102. Dialog options for TABLE.

_dlg variables

When you enable Dialog interface information in an ASSIGN or TABLE step, the system creates a second BP variable based on the Name field. For example, in Figure 12‑102, a variable named table is created that points to the control table, but because there is dialog interface information enabled, a second variable named table_dlg is created that contains that information. This auxiliary variable is always named for the Name entry, with _dlg appended.

_dlg variables can be accessed and manipulated, just like any other variable. You could include one in a SHOW statement, for example, to learn its structure. You can also create them explicitly, if you want to include a information in a Dialog for a variable that was not created by ASSIGN or TABLE.

To illustrate, the check box configuration in Figure 12‑97 is doing this Python equivalent:

xyz = False
xyz_dlg = {'interface': 1, 'target': 'early', 'label': 'Allow early matching'}

The drop down configuration in Figure 12‑98 is doing this Python equivalent:

loc = 'Plot AD157'
loc = 'Plot AD157'
loc_dlg = {'interface': 3, 'values': ('Plot AD157', 'Plot AE200', 'Plot AE201', 'Greenhouse'),
'label': 'Measurement location', 'target': 'loc'}

The edit box configuration in Figure 12‑99 is doing this Python equivalent:

abc = 4.5
abc_dlg = {'target': 'abc', 'description': 'Your best estimate', 'units': 'cm\u00b2',
'interface': 2, 'label': 'Damaged area', 'checkable': False, 'width': 0}

The checkable version of edit box does this:

abc = {'value': 4.5, 'checked': False}
abc_dlg = {'target': 'abc', 'description': 'Your best estimate', 'units': 'cm\u00b2',
'interface': 2, 'label': 'Damaged area', 'checkable': True, 'width': 0}

The radio button configuration in Figure 12‑100 is doing this Python equivalent:

loc = 'Plot AD157'
loc_dlg = {'interface': 8, 'values': ('Plot AD157', 'Plot AE200', 'Plot AE201', 'Greenhouse'),
'label': 'Where', 'target': 'loc'}

Things to consider

Some facts about DIALOGs:

  • When a DIALOG statement is encountered in the BP, the dialog is presented. It remains on the screen until the user presses one of the displayed buttons. If no buttons are specified, there will be one OK button by default.
  • While a DIALOG is being displayed, BP program execution remains on the BP's DIALOG step even if the user interacts with editable items (check boxes, edit boxes, etc.).
  • BP variables editable by a DIALOG receive their updated values as they are edited. Including a Cancel button, for example, does not mean that pressing Cancel undoes any edits that may have been made. (You can support that behavior, of course, but you have to program for it outside of the DIALOG step.)


EXEC performs the Python exec() function on the text in the 'Source' entry box, or on the file named by ‘Source’. A simple example in Figure 12‑103 illustrates: we use EXEC to define two variables.

Figure 12‑103. Defining two variables in an EXEC.

More complicated code can be put in a separate file and referenced by the EXEC. Figure 12‑104 illustrates how to add this capability to a BP.

Figure 12‑104. Adding extended functionality via EXEC.

Local vs global

If the Scope setting of an EXEC is Local, then variables defined in the EXEC are available only from the context in which the EXEC occurs. The Global option means whatever is defined in the EXEC is available anywhere (e.g., in any function) in the rest of the program. See Figure 12‑105.

Figure 12‑105 . Local (top) vs Global (bottom). The locally defined linearList is not available from within the MyFct subroutine.


A GROUP is a container for program steps. It has an ‘Enabled’ property that determines whether or not the contained steps execute at run time. Thus, GROUP provides a convenient way to enable/disable sections of your program.

Figure 12‑106. Example of an GROUP structure.


The IF step can be made into any of three types: IF, ELSE IF, and ELSE.

Figure 12‑107. Example of an IF structure.

While building a BP, there is nothing that ties any of these IF variations together, so it is up to you to arrange them appropriately.

  • IF always marks the start of a new IF structure.
  • After the IF, there can be as many ELSE IFs as you need.
  • ELSE is optional, there can be only one, and it must come last.

If there is a misplaced ELSE or ELSE IF, then you will get an error message:


The LOG statement cover all aspects of the normal LI-6800 log operations; it can open a log file, log a remark, log data, or close the file.

Open file

Figure 12‑108 illustrates opening a log file with a programmatically determined name. You can use File... to select an existing file, and modify the name in the edit box, or just type the name or expression into the edit box.

Figure 12‑108 . Opening a log file with a programamtically determined name.

If a log file is already open when a LOG [Open file] is executed, the file will be closed first, and the new file opened.

Record remark

Adds a remark string to the file. This is skipped if no log file is open.

Figure 12‑109. Logging a remark.

If you wish for some reason to retrieve the latest logged remark, it is available via LOG:LastRem in status dictionary.

Record data

LOG[RecordData] triggers a log event, or is just skipped if no log file is open. You can override the current log options for this event if you so choose.

Figure 12‑110. LOG allows you to temporarily override log options.

Close file

The LOG[Close file] option takes no parameters. If no file is open when this is executed, it does nothing.

Figure 12‑111. Closing a log file.


LOOP contains steps that execute repeatedly. It comes in five types: Count, Duration, Control, List and File.


If you wish to cycle a fixed number of times, use the LOOP [Count] option. You can define a variable to access the count (0, 1, ...). You can regulate the loop with ‘Minimum time per cycle’, otherwise it will be limited 0.1 seconds.

Figure 12‑112. Loop Count, 5 loops, index is x, and no timing regulation.


If you wish to cycle for some time duration, use the LOOP [Duration] option. You can define a variable that contains the number of seconds that program execution has been in the loop.

Figure 12‑113. LOOP [Duration], 5 seconds total, with timing via when new data is available (‘Min time = 0’)


If you wish to cycle through a list of items of any type, use LOOP [List]. On each pass through, the associated variable that you name is assigned to an item from the list. It also works on Table variables.

Figure 12‑114. LOOP [List] example.


If you wish to process lines in a file, one at a time, use LOOP [File]. It a file, and executes the loop once for each linen in the file. You define a variable that will contain the line for each loop. If you wish, you can have the line parsed, in which case the variable will be a list of the items found.

Figure 12‑115. Configuring LOOP [File].

See /home/licor/apps/system/tests/ This program parses three sample input files, listed below (spaces and tabs are shown as printable characters in the space and tab files). The files reside in /home/licor/apps/system/tests/inputs/.

Figure 12‑116. LOOP [List] example.

Note that in each case, the unparsed line is always a string, and the parsed pieces are always strings. Turning a string into a number in Python is easy (float() function), but you may not need to. If you were using these values to set a control, the SETCONTROL controls will do the conversion for you.


The PROPERTIES lets you programmatically pause a BP, and also controls the BP’s verbosity (run log output).

Figure 12‑117. Using the PROPERTY step to pause a program.

Verbose, which defaults to off, controls how much gets written to the run log. With Verbose set to False, the only output to the run log will be start and stop messages, SHOW output, and warnings and errors. With verbose set to True, nearly every step will contribute to the run log.

If the Pause property is true, the BP will pause when it encounters that step while running. This is useful for debugging purposes (see Debug mode), or indefinitely pausing a program until the user wishes to resume.


The RETURN step exits a DEFINE, or exits the main program.

There are no parameters associated with RETURN. If you wish to return a value from a DEFINE, use the pass-by-reference feature for a passed parameter (see Passing by value or reference).


RUN is how a BP can launch another BP.

Figure 12‑118. A BP that launches two other BPs.


SETCONTROL allows you to set a control or system constant. The button in the Target line will access the control dictionary. The Value line will have slightly different looks depending upon the control.

Figure 12‑119. The SETCONTROL interface varies with target.

If you wish to select the target at run time instead of at design time, then use the Target (from expression) field. This will override whatever the button label is. For example, if you wish to read targets and values from a file, you could put a SETCONTROL in a loop that reads the le, and each pass through the loop sets target to x[0] and value to x[1], assuming x held the parsed line, and each line held 2 items: target (string) and value (number or expression).

When the 'Value' is a ComboBox, as in the Dio1 example above, the non-fixed entry allows you to select the choice at run time, rather than design time. Table 12‑4 illustrates some entry choices for Dio1.

Table 12‑4. Options for entering SETCONTROL Dio1.
Typed in Value Result
high At design time, same as selecting high from the menu.
'high' At run time, evaluates to a string, so becomes high.
0 At run time, sets Dio1 like you had picked low.
xxx At run time, assuming you have defined xxx, and it evaluates to 'high', 'low', 'input', 1, 0, or -1, then this is fine.
'in'+'put' At run time, evaluates to a string ('input'), so same as input.
99-100 At run time, evaluates to -1, so same as input.


SHOW prints to the run log. You can specify a list of variables, or specify a formatted string.

Figure 12‑120. Using SHOW.


A TABLE is a named control table that can be executed by making it the target of a LOOP [List].

Figure 12‑121. TABLE are executed in a LOOP [list].

The LOOP will loop over the number of settings found in the top row of the table. Each pass through, it sets the table's row targets (top to bottom), to the value in that row's column. If an entry is blank, it skips that target. Thus, if only the first column in the table for a particular row has an entry, that value will only be set once.

Structure of a TABLE variable

Consider a TABLE with two controls, one for light intensity, and one color, and an auxiliary constant for wait times (Figure 12‑122).

Figure 12‑122. A table with two controls and an auxiliary constant.

A variable table is a Python dictionary with two keys:

  • "values" - a list, each item is a tuple containing a string (the target) and a list (list of setpoints).
  • "aux" - a dict, with keys corresponding to the strings (targets) in the "values" list. The keys for each item are:
    • "control": True or False
    • "staticmeta": True or False. If True, there will also be keys for "units" and "format".

Listing 12‑4. An example of a TABLE variable.

    "values": [
    "aux": {
        "Color_Qin": {
            "control": True,
            "staticmeta": False
        "wait": {
            "units": "mins",
            "format": ["f",1,2],
            "control": False,
            "staticmeta": True
        "Qin": {
            "control": True,
            "staticmeta": False

Custom executions

If you need to customize how a TABLE is handled during run time, then you should start with Figure 12‑123 which illustrates the functional equivalent of the standard processing that LOOP [List] provides.

Figure 12‑123. A template program for how to explicitly program the execution of a table.


WAIT has three types: Duration, Stability, Until a time of day, and for an Event or condition. All but the last type of wait will put a countdown on the Start screen and/or Monitor screen (when selected).

Figure 12‑124. Wait countdown.


WAIT [Duration] suspends execution for the specified amount of time.

Figure 12‑125. Wait duration.


WAIT [Stability] has two parts. Part 1 is the minimum time. From the end of that until the maximum time, the wait will be terminated if the current stability definition is met. In the interval between 30 seconds after the start of the wait, and 60 seconds before the maximum time, a match will occur if Early matching is True, and if the reference IRGAs (Cr and Hs) meet the following stability criteria:


Figure 12‑126. Wait [stability] example.


WAIT [Until] waits for a time of day. Figure 12‑127 shows multiple ways to achieve the same thing.

Figure 12‑127. Wait [until] example.

If no date is specified and the specified time has passed when the statement executes, the program will wait until the next day.

The ‘String’ format (lower left in Figure 12‑127) is an alternative way to specify time and date; the advantage is that allows you to programmatically specify it if you choose. To include a date, specify the stop time1 in the 'Format' box. Otherwise, just specify the string as decimal hours, or hh:mm, as illustrated in Table 12‑5.

Table 12‑5. Some examples of specifying time and date. The format string is not really needed unless you wish to specify a date along with the time.
[Date] time Format Interpreted as
10 10:00:00 am
5.5 05:30:00 am
14:22 14:22:00 pm
8:30:6 08:30:06 am
6 Dec 2019 12:33:45 %d %b %Y %H:%M:%S 6 Dec 2019 12:33:45


WAIT [Event] waits until the test you have specified becomes True. The example in Figure 12‑128 is as close as you may come to a game on the LI-6800. It simply times how long it takes you to get the flow rate2 below 400.

Figure 12‑128. The Wait [Event] example.


WHILE loops while the specified condition is True. The ‘Minimum time per cycle’ specifies the minimum time interval that will separate each cycle through the loop. Default is 0.1 seconds. Setting this to 0 means it will cycle when the next data set become available (nominally every 0.5 sec).

The example in Figure 12‑129 will loop until the sample cell flow rate exceeds 20 µmol/sec, so if you have the chamber closed and the pump running before running this program, it will loop until you either open the chamber, or stop the flow, or 1 minute has expired.

Figure 12‑129. WHILE example.