v5.0 / 11 of 23 / 01 sep 99 / gvg
* This chapter covers the operation of the VEE test sequencer in detail.
* The simplest way to introduce the Sequencer is to build a small "mock" test
system with it (you can get the source for it from the file
xsequenc.vee). This test consists of the simple sequencing of 3 test
routines ("DevTest1" through "DevTest3"), preceded by a routine to set up the
test system ("InitTest").
In reality, these are dummy routines that merely return a random number in
the range -1 through 11. The three test routines all have the form:
The "InitTest" routine simulates setting up the test procedure. In this
case, all it does is seed the random-number generator:
However, the Sequencer transactions consist of the sequence of tests to be
performed, not I/O transactions. In this case, four transactions need to be
set up.
The first is the "InitTest" routine. Click on the transaction field and you
get a complicated dialog:
The other fields in the dialog can be left at their defaults (it is, in fact,
impossible to set "LOGGING DISABLED"). While the "ENABLED" field can be used
to turn off this transaction, that obviously isn't desired here. Since the
idea here is to run "InitTest" and then directly run the test routines, the
"THEN CONTINUE" field can be left at its default, instead of being used to
specify one of the many alternatives available for sequencer actions on
completion of a transaction.
This done, the test transactions for the three test routines can be set up.
Clicking on the second field and modifying the transaction dialog
appropriately gives:
The other two tests are defined similarly, resulting in:
* Of course, the answer to that is simple: the test results are output
through the Sequencer's Log output pin. Unfortunately this simple answer
begs a nastier question: what is the format of this output, and what can be
done with it?
The answer to this question has two parts. First, the data provided for
logging output from the tests can be specified by selecting "Edit Default
Preferences" from the Sequencer's object menu. You get the usual tabfolder,
but with a tab for "Logging":
If there are not too many tests in the sequencer, a simple To String object
will suffice to do the job. For example, in this case:
The least painful involves a feature of the Logging Config tab. This tab has
a field:
So, if the UserFunction named logTest, say, writes the formatted I/O
transactions to a file:
* This fast tour of the Sequencer provides a basic understanding of the
object. This section builds on that understanding by a full description of
the Sequencer's features.
* The Sequencer object, as should be obvious by now, is used to control the
order of calling a series of UserFunctions, Compiled Functions, or Remote
Functions.
The Sequencer logs test results to the Log output pin, as well as
(optionally) to a UserFunction, Compiled Function, or Remote Function.
The Sequencer's Return output pin is used for returning a result when a
sequence has completed. By default, the Return output pin is zero, but a
transaction with a "Next Operation" of "Then Return" will set the Return
output pin to the specified value.
* The transactions are defined by clicking on the appropriate transaction
field. The transactions may be EXEC or TEST transactions (as set by toggling
the field in the upper left corner), and their parameters are set by dialogs.
EXEC transactions simply unconditionally execute a routine. They will not
test the routine against limits, nor perform logging. The EXEC transaction
dialog has the form:
The Sequencer always executes the transaction.
The Sequencer never executes this transaction (a NOP).
The transaction executes if the expression result is nonzero.
The transaction is not executed if the expression result is nonzero.
If either of the last two cases are selected, a new field appears that allows
the user to enter the name of an input pin or a function name:
The "THEN CONTINUE" field is a little trickier to describe. It defines what
operation the Sequencer will perform after performing the specified EXEC
transaction:
Goes to the next transaction in the Sequencer list. This is the default.
Quits executing transactions in this Sequencer and places the value of the
specified expression (which can call a function) on the Return output pin
of the Sequencer. The Sequencer object will then fire its output pins and
execution flow within the program will continue normally.
Continues operation at the transaction with the specified name.
Executes this transaction again, repeating up to the specified number of
times.
Stops execution of the Sequencer by generating an error condition with the
given error number.
Evaluates the given expression -- which may call a UserFunction, Compiled
Function, or Remote Function -- and uses the (string) result to determine
the next operation. Valid string results from the expression are:
... where "<expr>" is any valid HP VEE expression and "<name>" is the
name of a transaction in this Sequencer. This operation can be useful
when a UserFunction, possibly with user interaction, needs to determine
what action the Sequencer should perform next.
Finally, the description field is simply a comment field. Any useful text
can be placed there.
* The TEST dialog is similar, but contains more detail:
The "FUNCTION:" field allows specification of the test function, as in the
EXEC dialog. The LOGGING ENABLED field allows the transaction's results to
be logged, or be set to LOGGING DISABLED if that is not wanted.
The next two lines specify what the Sequencer does after executing the test
function. One line specifies what happens if the test passes, another what
happens if it fails. There are a wide number of options:
Finally, the "DESCRIPTION" field allows for a comment.
* The Sequencer's "Edit Default Preferences" allows specification of logging
options as:
Logging configuration can be set as follows:
A logging record will be present in the record on the Log output pin for
each transaction that has Logging Enabled. If a transaction is executed
more than once during one execution of the Sequencer, only the last
logging record for that transaction will be present in the record on the
Log output pin. If a transaction has not been executed during an
execution of the Sequencer, the logging record for that transaction will
contain "0" (Real) values for each field except the Name and Description
fields, which contain null strings.
This allows specification of a function that will be called after each
transaction that has Logging Enabled. To pass the logging record for the
current transaction to the function, use the reserved variable name
"ThisTest". The Log output pin will continue to operate in the same
manner as for the "Log to Output Pin Only" mode.
* An "Exec Trans" control input pin may also be added. The Exec Trans
control input executes only the transactions with the specified names in the
order given by a Text scalar or 1D array input.
All field expressions (such as ENABLED IF, FUNCTION, or spec limits) may
contain input pin names, UserFunction calls, Compiled Function calls, Remote
Function calls, HP VEE math functions, or record names of previously run
transactions.
* A VEE user had an interesting question. His program was supposed to query
the user for several different items of information, and he wanted to figure
out a way by which the user could cancel on a query and go back to make
changes in earlier queries.
The VEE Sequencer turned out to be an excellent tool for the job. Querying a
user and performing different actions on the replies is conceptually no
different from testing a machine and performing different actions on the
results, and can be easily used to perform the queries.
* Let's design a little query scheme using the Sequencer that asks the user
for name, rank, and serial number. The user can back out of the sequence at
any step of the query, and the existing values will not be changed.
In this example, these values are stored in three global variables, with the
simple names:
These variables can be initialized by a UserFunction named "Init". This
UserFunction is very simple, consisting of six Set Global (or Set Variable)
objects, one for each variable, plus a text constant containing the arbitrary
string "NULL" that is wired into all six.
* Performing the queries is also simple. They all basically request strings,
so we can use the same UserFunction for all three queries, and just provide
the UserFunction with parameters giving the prompt string and the name of the
variable to be updated.
We'll call this UserFunction "GetReply()". All it does is pop up a Text
Input dialogue box to query the user and get his or her reply. To allow the
Sequencer to test the results of the query, the UserFunction returns "1" if
the user makes an entry, and "0" if the user cancels the dialogue box.
The resulting UserFunction is very simple:
* This UserFunction is called by the Sequencer to perform the set of queries.
The first query asks for the user's name. The transaction is set up as
follows:
This transaction calls "GetReply()", providing a prompt of "Your name?", and
specifying that the return value be stored in the variable "newname". If
"GetReply()" returns a "1", the test passes and the Sequencer moves on to the
next transaction. If "GetReply()" returns a "0", the test fails and the
Sequencer exits on the THEN RETURN, and also putting an arbitrary value of 1
on the output pin.
In reality, you would probably want to use a somewhat more tactful prompt,
such as: "Please input your name." -- but I used a short prompt here just
to save space in the illustration.
* The second transaction asks for rank:
* The third transaction asks for serial number:
* These transactions define a sequence that steps forward through all three
queries, moving backwards through the sequence if the user cancels on the
inputs.
Remember, however, that the queries have put values into buffer variables, so
an "execute" Sequencer transaction has to be built to load the actual
variables from the buffer variables, calling a UserFunction named
"UpdateData()".
All "UpdateData()" does is use three Get Global (or Get Variable) objects to
get the values of "newname", "newrank", and "newserno", and three Set Global
(or Set Variable) objects to load the respective values into the variables
"name", "rank", and "serial number".
The fourth transaction looks like this:
Since the Sequencer executes transactions step by step, and this is the last
of the four, this transaction will not be executed unless the previous three
were. This allows the user to cancel all inputs up to the very last one
without changing the original values of the "name", "rank", and "serno"
variables.
* The final sample program is about as simple as you might want:
* This example was written using as conservative features of VEE as were
possible to allow it to work on older versions. It can be mildly streamlined
by using current VEE features.
Of course, this is an example, and has to be simple. A few comments for
changes and improvements can be provided:
More complicated decision making could be performed by using additional
transactions to test the value of a variable and branch appropriately.
For example, to generate a FOR loop, you could have a transaction before the
beginning of a loop that calls a function to initialize a variable to the
loop count. At the end of the loop, you could have a transaction that
decrements the value, tests it for equality to zero, and loops back to the
transaction just after the initialization transaction.
An UNTIL-BREAK loop could be devised by initializing a variable to 0,
testing to see if it has been set to 1 by one or more of the transactions in
the loop, and branching back if it is still 0.
However, one of the problems with the Sequencer is that it has enough
features to create really complicated solutions when a simpler one might be
much easier to write and maintain. In this case, the Sequencer proved to be
clearly the very best tool for the job.
[11.1] SEQUENCER -- SEQUENCER TRANSACTIONS
[11.2] SEQUENCER -- SEQUENCER LOGGING
[11.3] SEQUENCER -- THE FINE PRINT
[11.4] USING THE SEQUENCER TO PROMPT FOR USER INPUTS
[11.1] SEQUENCER -- SEQUENCER TRANSACTIONS
+------------------------------------------------+
| UserFunction: DevTest1 |
+----+---------------------------------------+---+
| | | |
| | | |
| | +--------------------------+ | |
| | | Formula | | |
| | +-----------------+--------+ | |
| | |[ random(-1,11) ]| Result +---->| X |
| | +-----------------+--------+ | |
| | | |
| | | |
+----+---------------------------------------+---+
| [ Done ] |
+------------------------------------------------+
Note the routine has an output to return the result of the "test". Such
routines could also have one or more inputs.
+----------------------------------------------------------------------+
| UserFunction: InitTest |
+----+-------------------------------------------------------------+---+
| | | |
| | | |
| | +---------------------------------------------------+ | |
| | | Formula | | |
| | +------------------------------------------+--------+ | |
| | | [randomseed((10^9)*fracPart(now()/100))] | Result +--->| X |
| | +------------------------------------------+--------+ | |
| | | |
| | | |
+----+-------------------------------------------------------------+---+
| [ Done ] |
+----------------------------------------------------------------------+
The final result is the following list of routines:
+-------------------------------------------+
| Edit UserFunction |
+------------+-----------------+------------+
| | InitTest | |
| | DevTest1 | |
| | DevTest2 | |
| | DevTest3 | |
| | | |
+------------+-----------------+------------+
|[InitTest ]|
+-------------------------------------------+
| [ OK ] [Cancel] |
+-------------------------------------------+
The Sequencer object is then used to link these test routines together. The
Sequencer appears to be an ordinary I/O transaction object:
+----------------------------------------------------+
| Sequencer |
+---+---------------------------------------+--------+
| |[ ]| |
| | | Return |
| | | |
| | | |
| | | |
| | | Log |
| | | |
+---+---------------------------------------+--------+
Note the "Log" pin, which outputs the results of the tests. The "Return" pin
can be ignored for now.
+-------------------------------------------------------------------------+
| Sequence Transaction |
+-------------------------------------------------------------------------+
| [ TEST: ] [ test1 ] [ ENABLED ] |
| SPEC NOMINAL: [.5 ] [ RANGE ] [0 ] [ <= ] ... [ <= ] [1 ] |
| FUNCTION: [testFunc(s) ] [ LOGGING ENABLED ] |
| [ IF PASS ] [ THEN CONTINUE ] |
| [ IF FAIL ] [ THEN CONTINUE ] |
| DESCRIPTION: [ ] |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
Note how the first field in the upper left corner says "TEST:". In this
case, the routine to be executed is not a test -- all it does is
initialize the system for true tests -- so clicking on that field gives the
alternative, an "EXEC:" transaction (which simply executes a function):
+-------------------------------------------------------------------------+
| Sequence Transaction |
+-------------------------------------------------------------------------+
| [ EXEC: ] [ test1 ] [ ENABLED ] |
| FUNCTION: [testFunc(s) ] [ LOGGING DISABLED ] |
| [ THEN CONTINUE ] |
| DESCRIPTION: [ ] |
| |
| |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
The only things that need to be done on this dialog are to change the test
name and function name appropriate, and add a description (if desired):
+-------------------------------------------------------------------------+
| [ EXEC: ] [ Init ] [ ENABLED ] |
| FUNCTION: [InitTest() ] [ LOGGING DISABLED ] |
| [ THEN CONTINUE ] |
| DESCRIPTION: [ Initialize test setup. ] |
| |
| |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
The test name -- "Init" -- is purely arbitrary and doesn't need to have
anything to do with the name of the function being called. The Sequencer
simply uses the test name as a handle to the transaction. (Each transaction
must have a unique name.)
+-------------------------------------------------------------------------+
| [ TEST: ] [ test1 ] [ ENABLED ] |
| SPEC NOMINAL: [5 ] [ RANGE ] [0 ] [ <= ] ... [ <= ] [10 ] |
| FUNCTION: [DevTest1() ] [ LOGGING ENABLED ] |
| [ IF PASS ] [ THEN CONTINUE ] |
| [ IF FAIL ] [ THEN CONTINUE ] |
| DESCRIPTION: [Device test 1. ] |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
Here the transaction is given an (also arbitrary) name. The test limits are
defined as being from 0 through 10, with the nominal value being 5. The
nominal value is simply for documentation in this case, it doesn't do
anything. The UserFunction name is given as "DevTest1()"; logging is enabled
and the Sequencer is instructed to proceed with the next test, whether the
current test passes or fails; and a short description is provided.
+---------------------------------------------------+
| Sequencer |
+---+--------------------------------------+--------+
| | Init | |
| | test1 0 <= (5) <= 10 Test trial 1! | Return |
| | test2 0 <= (5) <= 10 Test trial 2! | |
| | test3 0 <= (5) <= 10 Test trial 3! | |
| | | |
| | | Log |
| | | |
+---+--------------------------------------+--------+
Test limits can also be derived from a variable. The same program could be
implemented as follows:
+----------+ +--------------+
| Real | | Set Variable |
+----------+ +--------------+
| 0000: 0 +---->| TestLim |
| 0001: 10 | +-------+------+
+----------+ |
|
+---------------------------------+----------------------------------+
| Sequencer |
+---+-------------------------------------------------------+--------+
| | Init | |
| | test1 0 <= (5) <= 10 Test trial 1! | Return |
| | test2 0 <= (5) <= 10 Test trial 2! | |
| | test3 TestLim[0] <= (5) <= TestLim[1] Test trial 3! | |
| | | |
| | | Log |
| | | |
+---+-------------------------------------------------------+--------+
Now the test can be run. However, that begs the question: how does anyone
know what the results of the tests are?
[11.2] SEQUENCER -- SEQUENCER LOGGING
+-----------------------------------------------------------+
| Sequencer Properties |
+-----------+-----------+-----------+-----------+-----------+
| General | Colors | Fonts | Logging | Printing |
+-----------+-----------+-----------+ +-----------+
| +- Record Fields To Log ---------------------+ |
| | [x] Name [ ] Low Limit | |
| | [x] Result [x] Pass | |
| | [ ] Nominal [x] Time Stamp | |
| | [ ] High Limit [x] Description | |
| +--------------------------------------------+ |
| +- Logging Mode -----------------------------+ |
| | [Log to Output Pin Only] | |
| +--------------------------------------------+ |
| |
| |
| |
+-----------------------------------------------------------+
| [ OK ] [ Cancel ] [ Help ] |
+-----------------------------------------------------------+
Now for the actual output format. Given the settings shown above, running
the Sequencer sets the contents of the Log output pin to:
+----------------------------------------------------------------+
| Output Terminal Information |
+----------------------------------------------------------------+
| Name: [ Log ] Mode: [ Data ] |
| |
| Container Information |
| |
| +---------------------+ +-----------------------------+ |
| | Type: [ Record ] | Data: | Field Name Value | |
| | Shape: [ Scalar ] | | [ test1 ] [ Record Scalar ] | |
| +---------------------+ | [ test2 ] [ Record Scalar ] | |
| | [ test3 ] [ Record Scalar ] | |
| +-----------------------------+ |
| |
| [ OK ] [ Cancel ] |
+----------------------------------------------------------------+
The logging output is a single record, with individual subrecords for the
result of each test. Each of these subrecords has the format:
+-------------------------------+
| Record Field Data |
+-------------------------------+
| Field name Value |
| [ Name ] [test1 ] |
| [ Result ] [6.35 ] |
| [ Pass ] [1 ] |
| [ TimeStamp ] [62.9G ] |
| [Description] [Test trial 1!] |
+-------------------------------+
| [ OK ] [Cancel] |
+-------------------------------+
This record follows the format defined in the "Logging Config" dialog box.
Similarly, if a To File object is connected to the Log pin of the sequencer,
the output file will contain the following data:
{{"test1", 2.498779296875, 1, 62907213809.66, "Test trial 1!"},
{"test2", -0.1331787109375, 0, 62907213809.66, "Test trial 2!"},
{"test3", 2.3255615234375, 1, 62907213809.72, "Test trial 3!"}}
This is an extremely concise format that defines exactly the sequence of the
test results. Unfortunately, if all that is needed is a simple printout of
the test results, it's a pain to deal with because each subrecord has to be
sorted out individually.
+---------------------------------------------------------------------+
| To String |
+---+--------------------------------------------------------+--------+
| | WRITE TEXT A.test1.Name STR FW:6 LJ | |
| | WRITE TEXT A.test1.Result REAL FIX:2 FW:6 RJ | |
| | WRITE TEXT A.test1.Pass INT:1 FW:3 RJ | |
| | WRITE TEXT A.test1.TimeStamp TIME:HMS:H24 FW:12 RJ EOL | |
| | WRITE TEXT A.test2.Name STR FW:6 LJ | |
| | WRITE TEXT A.test2.Result REAL FIX:2 FW:6 RJ | |
| A | WRITE TEXT A.test2.Pass INT:1 FW:3 RJ | result |
| | WRITE TEXT A.test2.TimeStamp TIME:HMS:H24 FW:12 RJ EOL | |
| | WRITE TEXT A.test3.Name STR FW:6 LJ | |
| | WRITE TEXT A.test3.Result REAL FIX:2 FW:6 RJ | |
| | WRITE TEXT A.test3.Pass INT:1 FW:3 RJ | |
| | WRITE TEXT A.test3.TimeStamp TIME:HMS:H24 FW:12 RJ EOL | |
| | | |
+---+--------------------------------------------------------+--------+
This yields the output:
test1 4.39 1 13:01:20
test2 2.12 1 13:01:20
test3 2.90 1 13:01:20
* This sort of field-by-field dissection might prove painful in a test system
with a greater number of tests, but there are a number of roundabouts that
can avoid it.
[Log to Output Pin Only ]
Click on this and it changes to something of the form:
[Log Each Transaction To: ] [logTest(thisTest)]
This specifies that, after each individual test, the test result is sent to a
UserFunction named "logTest" (or some other arbitrary name) using a parameter
named "thisTest", whose name is not arbitrary, as the Sequencer uses it
to specify the test result.
+-----------------------------------------------------------------------+
| UserFunction: logTest |
+---+---------------------------------------------------------------+---+
| | | |
| | +------------------------------------------------------+ | |
| | | To File | | |
| | +---+--------------------------------------------------+ | |
| | | |To File: [ tmp.txt ]| | |
| | | | [X] Clear File At PreRun & Open | | |
| | | |--------------------------------------------------| | |
| | | | WRITE TEXT A.Name STR FW:6 LJ | | |
| A +--->| A | WRITE TEXT A.Result REAL FIX:2 FW:5 RJ | | |
| | | | WRITE TEXT A.Pass INT FW:2 RJ | | |
| | | | WRITE TEXT A.TimeStamp TIME:HMS:H24 FW:12 RJ EOL | | |
| | | | | | |
| | +---+--------------------------------------------------+ | |
| | | |
+---+---------------------------------------------------------------+---+
| [ Done ] |
+-----------------------------------------------------------------------+
-- then the formatted file can be retrieved and displayed after the Sequencer
has completed its operations:
from Sequencer Sequence-Out pin
|
+----------------+----------------+ +----------------------------+
| From File | | Logging AlphaNumeric |
+-----------------------------+---+ +----------------------------+
| From File: [ tmp.txt ] | | | test1 1.78 1 12:30:07 |
|-----------------------------| | | test2 10.41 1 12:30:07 |
|[READ TEXT x STR ARRAY:* ]| X +---->| test3 10.92 1 12:30:08 |
| | | | |
| | | | |
| | | | |
+-----------------------------+---+ +----------------------------+
* One obnoxious feature of Sequencer logging is that you don't get any
display of information until the Sequencer has completed its operations. To
correct this (as noted in earlier chapters), a set of display functions were
added in VEE 3.1:
showPanel( UFname )
showPanel( UFname, x, y )
showPanel( UFname, x, y, width, height )
hidePanel( UFname )
These functions allow display of information while the Sequencer is
conducting its tests. You create a UserFunction with a panel view to provide
display output -- named, say, "Disp()", which displays a single item on an
Alphanumeric display -- and then your test functions can display this panel
by invoking:
showPanel("Disp")
Once it is visible, test functions can display data in the panel by invoking
that UserFunction:
Disp("This is a test!")
The panel will go away at the end of the program or when a test function uses
"hidePanel()" to conceal it.
[11.3] SEQUENCER -- THE FINE PRINT
+---------------------------------------------------+
| Sequencer |
+---+--------------------------------------+--------+
| |[ ]| |
| | | Return |
| | | |
| | | |
| | | |
| | | Log |
| | | |
+---+--------------------------------------+--------+
These functions are called through sequence transactions. After evaluating
the expression, a transaction compares the value returned against a test
spec. The sequencer then evaluates the next transaction. This transaction
may be conditionally selected by the Sequencer according to the results of
the previous test.
+-------------------------------------------------------------------------+
| Sequence Transaction |
+-------------------------------------------------------------------------+
| [ EXEC: ] [ test1 ] [ ENABLED ] |
| FUNCTION: [testFunc(s) ] [ LOGGING DISABLED ] |
| [ THEN CONTINUE ] |
| DESCRIPTION: [ ] |
| |
| |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
The "EXEC:" field is followed by the transaction name field. This field
contains a unique name that identifies the transaction. The ENABLED field
that follows it can have four values:
[ DISABLED IF:] [A ]
[ ENABLED IF:] [A ]
The "FUNCTION:" field is followed by the name of the function. The LOGGING
DISABLED field is fixed in this transaction and cannot be changed.
+-------------------------------------------------------------------------+
| Sequence Transaction |
+-------------------------------------------------------------------------+
| [ TEST: ] [ test1 ] [ ENABLED ] |
| SPEC NOMINAL: [.5 ] [ RANGE ] [0 ] [ <= ] ... [ <= ] [1 ] |
| FUNCTION: [testFunc(s) ] [ LOGGING ENABLED ] |
| [ IF PASS ] [ THEN CONTINUE ] |
| [ IF FAIL ] [ THEN CONTINUE ] |
| DESCRIPTION: [ ] |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
The name and ENABLED fields operate the same as they do for EXEC
transactions. The second line of the dialog is different, however. It
specifies the test limits or bounds for the function to be called. It has a
variety of forms:
SPEC NOMINAL: [.5 ] [ RANGE ] [0 ] [ <= ] ... [ <= ] [1 ]
SPEC NOMINAL: [.5 ] [ RANGE ] [0 ] [ < ] ... [ <= ] [1 ]
SPEC NOMINAL: [.5 ] [ RANGE ] [0 ] [ <= ] ... [ < ] [1 ]
SPEC NOMINAL: [.5 ] [ RANGE ] [0 ] [ < ] ... [ < ] [1 ]
SPEC NOMINAL: [.5 ] [ LIMIT: ] ... [ > ] [1 ]
SPEC NOMINAL: [.5 ] [ LIMIT: ] ... [ >= ] [1 ]
SPEC NOMINAL: [.5 ] [ LIMIT: ] ... [ < ] [1 ]
SPEC NOMINAL: [.5 ] [ LIMIT: ] ... [ <= ] [1 ]
SPEC NOMINAL: [.5 ] [ LIMIT: ] ... [ == ] [1 ]
SPEC NOMINAL: [.5 ] [ LIMIT: ] ... [ != ] [1 ]
SPEC NOMINAL: [.5 ] [ TOLERANCE:] + [1 ] - [1 ]
SPEC NOMINAL: [.5 ] [%TOLERANCE:] + [1 ]% - [1 ]%
This should be largely self-explanatory. Note that the "SPEC NOMINAL:" field
is merely for documentation, except in the case of the "TOLERANCE" and
"%TOLERANCE" settings. Note that all such tests are done in the same way as
the Comparator object. The test result may be a waveform, and the test
limit(s) may be another waveform, or an array of type Coord. The test is
performed to 6 significant digits. A tolerance of 0 may be specified.
[ IF PASS ] [ THEN CONTINUE ]
[ IF PASS ] [ THEN RETURN: ] [1 ]
[ IF PASS ] [ THEN GOTO: ] [test1 ]
[ IF PASS ] [ THEN REPEAT ] MAX TIMES: [3 ]
[ IF PASS ] [ THEN ERROR: ] [10 ]
[ IF PASS ] [ THEN EVALUATE: ] ["RETURN 1"]
[ IF PASS CALL: ] [passProc(1) ] [ THEN CONTINUE ]
[ IF PASS CALL: ] [passProc(1) ] [ THEN RETURN: ] [1 ]
[ IF PASS CALL: ] [passProc(1) ] [ THEN GOTO: ] [test1 ]
[ IF PASS CALL: ] [passProc(1) ] [ THEN REPEAT ] MAX TIMES: [3 ]
[ IF PASS CALL: ] [passProc(1) ] [ THEN ERROR: ] [10 ]
[ IF PASS CALL: ] [passProc(1) ] [ THEN EVALUATE: ] ["RETURN 1"]
[ IF FAIL ] [ THEN CONTINUE ]
[ IF FAIL ] [ THEN RETURN: ] [1 ]
[ IF FAIL ] [ THEN GOTO: ] [test1 ]
[ IF FAIL ] [ THEN REPEAT ] MAX TIMES: [3 ]
[ IF FAIL ] [ THEN ERROR: ] [10 ]
[ IF FAIL ] [ THEN EVALUATE: ] ["RETURN 1"]
[ IF FAIL CALL: ] [FailProc(1) ] [ THEN CONTINUE ]
[ IF FAIL CALL: ] [FailProc(1) ] [ THEN RETURN: ] [1 ]
[ IF FAIL CALL: ] [FailProc(1) ] [ THEN GOTO: ] [test1 ]
[ IF FAIL CALL: ] [FailProc(1) ] [ THEN REPEAT ] MAX TIMES: [3 ]
[ IF FAIL CALL: ] [FailProc(1) ] [ THEN ERROR: ] [10 ]
[ IF FAIL CALL: ] [FailProc(1) ] [ THEN EVALUATE: ] ["RETURN 1"]
These transactions should be self-explanatory, as long as the THEN CONTINUE
action explanations for EXEC are remembered. Note that a THEN REPEAT action
will repeat the specified number of times, and then the Sequencer will move
on to the following action in the list. Note also that the return values of
functions called by IF PASS CALL or IF FAIL CALL are ignored.
+-----------------------------------------------------------+
| Sequencer Properties |
+-----------+-----------+-----------+-----------+-----------+
| General | Colors | Fonts | Logging | Printing |
+-----------+-----------+-----------+ +-----------+
| +- Record Fields To Log ---------------------+ |
| | [x] Name [ ] Low Limit | |
| | [x] Result [x] Pass | |
| | [ ] Nominal [x] Time Stamp | |
| | [ ] High Limit [x] Description | |
| +--------------------------------------------+ |
| +- Logging Mode -----------------------------+ |
| | [Log to Output Pin Only] | |
| +--------------------------------------------+ |
| |
The logging fields are defined as:
[11.4] USING THE SEQUENCER TO PROMPT FOR USER INPUTS
name
rank
serno
Since the user can input new values but back out before completing input, the
input values he or she provides have to be buffered in a separate set of
variables, which can be conveniently named:
newname
newrank
newserno
* The first thing our sample program has to do is initialize these variables.
It's not really necessary to initialize the buffer variables, since they
won't be used until somebody actually loads them, but it is a good
programming practice to always initialize variables to prevent unpleasant
surprises.
+------------------------------------------------------------------+
| GetReply |
+---------+--------------------------------------------------------+
| | |
| | +---+ |
| prompt +---+ | 1 +--------------------+ |
| | | +-+-+ | |
| | | | | |
| | | +----------+----------+ | |
| | | | Text Input | | |
| | | +--------+---+--------+ +-->+-----+ |
| | +-->| Prompt | | Value +--------+ | JCT +--->|
| | | | | Cancel +---+ | +-->+-----+ |
| | +--------+---+--------+ | | | |
| | +-+-+ | | |
| | | 0 +--|--+ |
| | +---+ | |
| | | +----------+ |
| | +-->| Set | |
| varname +----------------------------------------->| Global | |
| | name +----------+ |
| | |
+---------+--------------------------------------------------------+
The core of this UserFunction is a Text Input dialogue box, with the "Prompt"
pin brought out to allow it to be defined as a parameter. A Set Global (or
Set Variable) object allows you to set the value of a variable, whose name is
also input as a parameter. The UserFunction puts a value of "1" on the
output, which is overwritten by a "0" if the "Cancel" pin is activated.
+-------------------------------------------------------------------------+
| Sequence Transaction |
+-------------------------------------------------------------------------+
| [ TEST: ] [ Query1 ] [ ENABLED ] |
| SPEC NOMINAL: [ 1 ] [ LIMIT ] [ == ] [1 ] |
| FUNCTION: [GetReply("Your name?","newname")] [ LOGGING DISABLED ] |
| [ IF PASS ] [ THEN CONTINUE ] |
| [ IF FAIL ] [ THEN RETURN: ] [ 1 ] |
| DESCRIPTION: [ ] |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
This defines a test transaction named "Query1", which tests for a limit equal
to "1". That is, the test succeeds if the value is "1", and fails if it is
anything else. The "SPEC NOMINAL" is set to "1", since that's the expected
proper return value, but it's largely irrelevant in this example.
+-------------------------------------------------------------------------+
| Sequence Transaction |
+-------------------------------------------------------------------------+
| [ TEST: ] [ Query2 ] [ ENABLED ] |
| SPEC NOMINAL: [ 1 ] [ LIMIT ] [ == ] [1 ] |
| FUNCTION: [GetReply("Your rank?","newrank")] [ LOGGING DISABLED ] |
| [ IF PASS ] [ THEN CONTINUE ] |
| [ IF FAIL ] [ THEN GOTO: ] [ Query1 ] |
| DESCRIPTION: [ ] |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
This is very similar to the first test transaction, except for a different
name ("Query2"), different parameters for "GetReply()" ("Your rank?" and
"newrank"), and a different action on test failure. Instead of performing a
THEN RETURN, it does a THEN GOTO and jumps back to the first transaction,
"Query1".
+-------------------------------------------------------------------------+
| Sequence Transaction |
+-------------------------------------------------------------------------+
| [ TEST: ] [ Query3 ] [ ENABLED ] |
| SPEC NOMINAL: [ 1 ] [ LIMIT ] [ == ] [1 ] |
| FUNCTION: [GetReply("Serial number?","newserno")] [ LOGGING DISABLED ] |
| [ IF PASS ] [ THEN CONTINUE ] |
| [ IF FAIL ] [ THEN GOTO: ] [ Query2 ] |
| DESCRIPTION: [ ] |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
This is almost the same as the second transaction, except for the transaction
name ("Query3"), different parameters for "GetReply()" ("Serial number?" and
"newserno"), and a THEN GOTO on failure back to the second transaction,
"Query2".
+-------------------------------------------------------------------------+
| Sequence Transaction |
+-------------------------------------------------------------------------+
| [ EXEC: ] [ Update ] [ ENABLED ] |
| FUNCTION: [ UpdateData()] [ LOGGING DISABLED ] |
| [ THEN CONTINUE ] |
| DESCRIPTION: [ ] |
| |
| |
| |
| [ OK ] [Cancel] |
+-------------------------------------------------------------------------+
This transaction is named "Update", and all it does is call "UpdateData()".
Nothing to it.
+-----------+
| Call Init |
+-----+-----+
|
+-------------------------+--------------------------+
| Sequencer |
+---+---------------------------------------+--------+
| | Query1(1) == 1 | |
| | Query2(1) == 1 | Return |
| | Query3(1) == 1 | |
| | Update | |
| | | Log |
| | | |
+---+---------------------+-----------------+--------+
|
+----------+---------+ +-------------+
| Get Global: name +--->| Wyle Coyote |
+----------+---------+ +-------------+
|
+----------+---------+ +-------------+
| Get Global: rank +--->| Predator |
+----------+---------+ +-------------+
|
+----------+---------+ +-------------+
| Get Global: serno +--->| 1 |
+----------+---------+ +-------------+
This displays some representative user inputs.