LAST PAGE  BACK TO INDEX  NEXT PAGE

[12.0] VEE Control Flow

[12.0] VEE Control Flow

v5.0 / 12 of 23 / 01 sep 99 / gvg

* VEE control flow is a tricky subject. The propagation rules are a little devious, though when analyzed are usually perfectly logical, and the only way to get a realistic grasp of them is through walking through examples.

It is difficult for someone who is experienced in working with VEE to remember how tricky the learning curve is. Concepts that seem difficult to the newcomer suddenly seem perfectly familiar, are taken for granted, and the difficulty is forgotten.

This chapter provides an overview of VEE control


[12.1] CONTROL FLOW OVERVIEW
[12.2] ELEMENTARY CONTROL FLOW
[12.3] ADVANCED CONTROL FLOW
[12.4] ERROR HANDLING
[12.5] PROPAGATION PROBLEMS

 BACK TO INDEX

[12.1] CONTROL FLOW OVERVIEW

* VEE control flow can be understood by analogy with a number of different concepts. It has some similarities to digital logic, is in some ways like the relay-ladder logic used in industrial controllers, is even to a degree like laying out track for a model train set.

Most of all, however, it is still has much in common with a normal sequential programming language, in particular in that (despite any initial impression that VEE might give) you can't do two different things at the same time, and that operations will follow each other in a sequence, though one which is not necessarily as deterministic as in a conventional language.

To get started, here are some simple rules of VEE style:

One of the common remarks made by users having ghostly problems with VEE is: "I deleted the object, replaced it with a new one of the same type, and then it worked."

This is an strong indication of an error in control-flow design. The reason such a substitution can make the program work is because VEE's execution order depends on the order in which objects were added if you haven't explicitly forced the execution to operate in a specific sequence.

Similarly, some programs that worked perfectly well in VEE 3.X don't work at all in VEE 4.x because the execution order has changed (while remaining legal under VEE propagation rules. There are also some peculiarities to VEE execution under VEE 4.x compiled mode that are different from VEE 3.x).

Sometimes the sequence of execution between different objects doesn't matter, sometimes it matters a great deal. This chapter will provide you with information on how to make that judgement and otherwise deal with control-flow problems.

 TOP OF PAGE

[12.2] ELEMENTARY CONTROL FLOW

* Writing VEE programs requires a grasp of how the core control constructs work in controlling programs. The simplest control is in generating a simple loop. If you want to generate a simple count, you can use a For Count object:


                        +----------------------+
                        | Logging Alphanumeric |
                        +----------------------+
   +---------------+    | 6                    |
   | For Count: 10 +--->| 7                    |
   +---------------+    | 8                    |
                        | 9                    |
                        +----------------------+ 
 
Note that the For Count counts from 0 to 9, not 1 to 10. Counter objects can be nested, of course:

  +---------------+
  | For Count: 10 +---+
  +-------+-------+   |
          |           |
          |   +-------+-------+   +---------+
          |   | For Count: 10 +-->| Counter +-->
          |   +---------------+   +---------+
          |
      +---+---+ 
      | Beep  |
      +-------+ 
 
Note how the outer-loop counter generates a "beep" through its sequence-out pin when it's done. This illustrates an important feature of how such looping objects work: they don't generate a sequence-out pulse until after everything they are driving has executed.

* If you want to generate an endless loop, you can use an Until Break object:


   +-------+
   | Until |
   | Break +----+ 
   +-------+    |        +-----------------------------+
                |        |        AlphaNumeric         |
            +---+---+    +-----------------------------+
            | now() +--->|   Sun 19/Feb/1995 13:19:16  |
            +-------+    +--------------+--------------+
                                        |
                                  +-----+-----+
                                  | Delay: 1  |
                                  +-----------+
 
I add a delay here so the AlphaNumeric won't update more often than once a second. Actually, an On Cycle would allow you to generate a container to drive the "now()" object with any delay that you like and so would be preferred in this case, but I will be developing the use of Until Break in following examples, and might as well be consistent.

You can set the time format though the "Edit Properties" entry in the AlphaNumeric's object menu. The number formats include a set of time formats for date and time, date, or time.

But what if you want to bail out of this loop at some time? This is a little tricky. One possible approach is to just add an OK button to drive a Break object to break out of the loop:


   +-------+
   | Until |
   | Break +----+----------+ 
   +-------+    |          |        +-----------------------------+
                |          |        |        AlphaNumeric         |
                |      +---+---+    +-----------------------------+
                |      | now() +--->|   Sun 19/Feb/1995 13:19:16  |
                |      +-------+    +--------------+--------------+
                |                                  |
             +--+--+                         +-----+-----+
             | OK  +---+                     | Delay: 1  |
             +-----+   |                     +-----------+
                       |
                   +---+---+
                   | Break |
                   +-------+
 
However, the approach of using two parallel paths has a major drawback: there is no guarantee that one path will be executed. One path might be executed all the time, or the other path might be executed all the time, or execution might be balanced between the two. There is nothing in the program to determine what will happen.

This ambiguity would occasionally lead to troubles with VEE 3.X, but when VEE 4.0 came out, the troubles became blatant and obvious. In reality, the same effect can be obtained just by adding an OK Button and a Stop object as a separate thread:


   +-------+           +------+
   | Until |           | Quit +------+
   | Break +--+        +------+      |
   +-------+  |                  +---+---+
              |                  | Stop  |
              |                  +-------+
              |
              |       +-----------------------------+  
              |       |        AlphaNumeric         |
          +---+---+   +-----------------------------+
          | now() +-->|   Sun 19/Feb/1995 13:19:16  |
          +-------+   +--------------+--------------+
                                     |
                               +-----+-----+
                               | Delay: 1  |
                               +-----------+
 
But what if the program has other threads that can't be halted? Then a Toggle button can be wired into the program to cause it to break out:

   +-------+
   | Until |
   | Break +--+
   +-------+  |           +-------------------+
              |           |    If/Then/Else   |
         +----+----+      +---+--------+------+
      +->| Toggle  +--+-->| A | A == 1 | Then +---------------+
      |  +----+----+  |   +---+--------+------+               |
      +-------|-------+                                   +---+---+
              |                                           | Break |
              |        +-----------------------------+    +-------+
              |        |        AlphaNumeric         |
          +---+---+    +-----------------------------+
          | now() +--->|   Sun 19/Feb/1995 13:19:16  |
          +-------+    +--------------+--------------+
                                      |
                                +-----+-----+
                                | Delay: 1  |
                                +-----------+
 
The Toggle is wired back to its Reset pin. If a user clicks on the Toggle with a mouse, it is set to 1, and so the Break object is fired. Otherwise, control is passed on to the rest of the program. (This particular trick is used in examples in earlier chapters.)

The Toggle should be configured to initialize to a 0 value to ensure that the program starts up correctly. This program's actions are much more predictable than those of the previous program.

* That said, now let's mix things up a little. Suppose you want to generate a count over and over again. One user tried this trick:


   +-------+
   | Start |
   +---+---+
       |
       +--->+-----+
            | JCT +----+            +----------------------+
       +--->+-----+    |            | Logging Alphanumeric |
       |               |            +----------------------+
       |       +-------+-------+    | 6                    |
       |       | For Count: 10 +--->| 7                    |
       |       +-------+-------+    | 8                    |
       |               |            | 9                    |
       +---------------+            +----------------------+
 
However, this only counted from 0 to 9 once. I was appalled at this since I could take one look at it and know it wasn't likely to work. Then I realized I couldn't actually say why it wouldn't work. It was just that after having played with VEE for a long time I had a feel for what would work and what wouldn't. (This construct is actually illegal in VEE 4.X.)

What would work was of course the Until Break again:


   +-------+
   | Until |
   | Break +---+            +----------------------+
   +-------+   |            | Logging Alphanumeric |
               |            +----------------------+
       +-------+-------+    | 6                    |
       | For Count: 10 +--->| 7                    |
       +---------------+    | 8                    |
                            | 9                    |
                            +----------------------+
 
* Anyway, given these techniques I can now demonstrate how to create a general architecture for interactive VEE programs. Let's consider a simple program where the user can select one of two actions or exit the program by clicking on the appropriate Toggle buttons; this program has the form:

  +-------+
  | Until |
  | Break +---+
  +-------+   |          +--------------+
              |          | If/Then/Else |
          +---+---+      +-------+------+
       +->| Key 1 +--+-->| A==1  | Then +--+
       |  +---+---+  |   +-------+------+  |
       +------|------+                     | 
              |                  +---------+----------+
              |                  |        Text        |
              |                  +--------------------+
              |                  | You pressed key 1! +--+
              |                  +--------------------+  |
              |                                          |
              |          +--------------+                |
              |          | If/Then/Else |                |
          +---+---+      +-------+------+                |
       +->| Key 2 +--+-->| A==1  | Then +--+             |
       |  +---+---+  |   +-------+------+  |             |
       +------|------+                     |             |
              |                  +---------+----------+  |
              |                  |        Text        |  +-->+-----+
              |                  +--------------------+      | JCT +--+
              |                  | You pressed key 2! +----->+-----+  |
              |                  +--------------------+               |
              |                                                       |
              |          +--------------+                             |
              |          | If/Then/Else |              +--------------+
          +---+---+      +-------+------+              |
       +->| Quit  +--+-->| A==1  | Then +--+           |  +--------------+
       |  +-------+  |   +-------+------+  |           |  | AlphaNumeric |
       +-------------+                     |           |  +--------------+
                                       +---+---+       +->|              |
                                       | Break |          +--------------+
                                       +-------+
 
The concept is simple: each separate action is positioned in a ladder of selections, and each action ends in a Next object to drive the next iteration of the Until Break object. You can add more actions as you need to.

Note the implication of this architecture: the path that is executing has to complete before another path can be executed. If the path that is being executed takes a long time to complete, you'll wait until it gets finished before you do something else.

 TOP OF PAGE

[12.3] ADVANCED CONTROL FLOW

* It is not a great leap forward from the techniques outlined in the section above to define how to handle more complicated VEE control tasks.

For an example, consider a VEE program that allows the user to select one of several tasks, or have a task initiated by a service request (SRQ) from an instrument. The following program (see xsrqtest.vee for the source) does this task:


   +-------+   +-----------+          +--------------+
   |  ID   |   |    Toggle |          | If/Then/Else |
   | 3478  |   |       +---+---+      +--------------+
   +---+---+   |    +->| Quit  +-+--->|     A==1     +--------+
       |       |    |  +---+---+ |    +--------------+        | 
   +---+---+   |    +------|-----+                        +---+---+
   | Until |   |           |          +--------------+    | Break |
   | Break +---+    Toggle |          | If/Then/Else |    +-------+
   +-------+          +----+----+     +--------------+
                   +->| Task 1! +-+-->|     A==1     +--------+
                   |  +----+----+ |   +--------------+        |
                   +-------|------+                      +----+----+
                           |          +--------------+   | TASK 1! +--> T1
                    Toggle |          | If/Then/Else |   +---------+
                      +----+----+     +--------------+
                   +->| Task 2! +-+-->|     A==1     +--------+
                   |  +----+----+ |   +--------------+        |
                   +-------|------+                      +----+----+
                           |          +--------------+   | TASK 2! +--> T2
                           |          | If/Then/Else |   +---------+   
                    +------+------+   +--------------+   
    Interface Event | SRQ: hpib7  +-->|     A!=0     +-------+
                    +-------------+   +--------------+       |
                                                      +------+------+
                                         Device Event | Spoll: 3478 |
                                                      +------+------+
                                                             |
       T1  --->+-----+   +---------+                    +----+----+
       T2  --->| JCT +-->| Message |               Text |   SRQ!  +--> SRQ
       SRQ --->+-----+   |   Box   |                    +---------+
                         +---------+
 
The program is driven by an Until Break object. The Until Break object drives the four parallel paths within the program -- controlled by three OK buttons ("Task 1", "Task 2", "Quit") and the Interface Event object ("SRQ: hpib7") -- and an outer loop that guarantees repeated execution of the paths.

The two paths defined by the "Task 1" and "Task 2" buttons simply display appropriate text ("TASK 1!" and "TASK 2!") in the Message Box to the right, while the path defined by the "Quit" button simply stops the program.

The interesting part of the program is the SRQ handling component, of course. Note that a 3478 State Driver is used at the beginning of the program to set a 3478 DMM's SRQ mask to 63; this allows you to assert an SRQ by pressing a button on the front panel of the DMM.

This done, the path that handles the SRQ simply uses the Interface Event object to wait for the SRQ. It is set as follows:


                   |
   +---------------+---------------+
   |           SRQ: hpib7          |
   +-----------------------+-------+
   |  Interface: [ hpib7 ] |       |
   |     Action: [NO WAIT] | event +-->
   |      Event: [  SRQ  ] |       |
   +-----------------------+-------+
 
When an SRQ occurs, the Interface Event object then fires off the Device Event object to do a serial poll, which clears the SRQ on the 3478:

                     |
   +-----------------+------------------+
   |           SRQ: hpib7               |
   +---------------------------+--------+
   | Device: [ 3478 (hp3478) ] |        |
   |  Event: [     Spoll     ] | status +-->
   | Action: [    NO WAIT    ] |        |
   |   Mask: [      #H0      ] |        |
   +---------------------------+--------+
 
Since NO WAIT is set, this object does the serial poll and then proceeds (firing off a text object to display that an SRQ has occurred); the mask value is irrelevant. (You can also do a WAIT SPOLL through a Direct I/O object if desired.)

Operating the example is simple; you run it and click the "Task 1" or "Task 2" buttons to get the appropriate pop-up display -- then if you press the SRQ button on the front of the 3478 , you get the "SRQ!" display output -- and go back to perform another task. The program stops when you click on the "Quit" button.

* For another example along this line, consider a user who wanted to be able to execute one of three different UserFunctions -- FunctionA, FunctionB, or FunctionC -- and then have his program continue to execute the last selected action. This could be done with the following program (see xpgmfunc.vee for the source):


   +-------+
   | Until |                                +------+
   | Break +--+                             | Quit +--+
   +-------+  |                             +------+  |
              |                                       |
    +---------+--------+                          +---+---+
    | Execute Function +--+                       | Stop  |
    +------------------+  |                       +-------+
     OK Button            |			  
                  +-------+-------+
                  | Radio Buttons |   +-----------+  +-----------+
                  +---------------+   |  Formula  |  |           |  
                  | <*> FunctionB |   +-----------+  |   +-------+-------+
                  | < > FunctionB +-->| asText(A) +--|-->| Call Function |
                  | < > FunctionC |   +-----+-----+  |   +---------------+
                  +---------------+         |        |
				            +--------+
 
This program calls three different functions -- FunctionA, FunctionB, and FunctionC (all they do is pop up a message box indicating "Task A!", "Task B!", or "Task C!"). The scheme is quite simple: An OK button fires off a Radio Buttons box that contains a list of the functions; the selected entry is converted into text and then sent into a Call Function box.

* For another applied problem in control flow, one of our HP support people had a related problem where he wanted to generate a strip chart that would be cleared every certain number of points, or whenever the user clicked a button. Interesting idea, but doing it isn't intuitive.

The following program (see xclstrip.vee for the source) shows how it's done:


   +-------+
   | Until +--+
   | Break |  |
   +-------+  |
              |
      +-------+-------+                                              |
      | Random Number +--------------------------------------------->|Trace 1]
      +-------+-------+                                              |
	      |                                     +------+         |
	      |                                     | Quit +--+      |
              |                                     +------+  |      |
	      |                                               |      |
              |                                           +---+---+  |
              |                                           | Stop  |  |
              |                                           +-------+  |
      +-------|-------+                                              |
      |  +----+----+  |   +-----------------------------------+      |
      +->| Toggle  +--+   |           If/Then/Else            |      |
         +----+----+  |   +-------+--------------------+------+      |
      Reset   |       +-->|[A Any]|[(A==1) OR (B==100)]|[Then]+--+-->|[Clear]
              |           |       |                    |      |  |   |
     +--------+       +-->|[B Any]|                    |[Else]|  |
     |                |   +-------+--------------------+------+  |
     +-->+---------+  |                                          |
         | Counter +--+                                          |
     +-->+---------+                                             |
     | Clear                                                     |
     |                                                           |
     +-----------------------------------------------------------+ 
 
An Until Break object clocks the program. It triggers a sequence of random numbers that are driven into the Strip Graph object (which is only shown as a set of input pins at the right of the diagram).

The Strip Graph is reset every 100 times by a Counter driving an If/Then/Else object. The output of the If/Then/Else is fed back to clear the Counter so the count can begin over again. It is also reset by the Toggle button.

 TOP OF PAGE

[12.4] ERROR HANDLING

* One difficult concept to deal with in VEE is error handling -- that is, how to perform an action and either repeat the action or continue after an error occurs.

A simple way to show how to handle this is with a dialog box to represent an action that can have different outcomes, as the following program (check xerrdemo.vee for the source) shows:


   +-------+
   | Until |
   | Break +------------------------+
   +---+---+                        |
       |                        +---+---+
       |                        | Beep  |
       |                        +---+---+
       |                            |
       |       +--------------------+--------------------+
       |       |               Message Box               |
       |       +--------------------------------+--------+
       |       | Message [ I/O Error          ] | Abort  +-------------+
       |       | Symbol  [(!)] [ Exclamation  ] | Retry  +--+          |
       |       | Buttons [ Abort Retry Ignore ] | Ignore |  |          |
       |       | Default [       Abort        ] |        |  |          |
       |       +--------------------+-----------+--------+  |          |
       |                            |                       |          |
       |                        +---+---+               +---+---+  +---+---+
       +-------------+          | Break |               | Next  |  | Stop  |
                     |          +-------+               +-------+  +-------+
                     |
  +------------------+-----------------+
  |              Message Box           |
  +-------------------------------+----+ 
  | Message [ ALL DONE!         ] |    |
  | Symbol  [(i)] [ Information ] | OK |
  | Buttons [         OK        ] |    |
  | Default [         OK        ] |    |
  +-------------------------------+----+
 
This program pops up a Message Box to ask if you want to "Abort Retry Ignore". If you "Abort", a Stop object is executed to stop the program; if you "Retry", you get a "Next" loop to try again. If you "Ignore", you get a "Break" that turns off the Until Break that then sequences down to the Message box that tells you the program is over.

Note how the element(s) to be executed sequentially after the "I/O" loop are connected to the sequence-out pin of the Until Break. They are not connected to any of the loop elements. Note also that you could connect the Break object to the "Ignore" pin instead of the sequence-out pin and it would work all the same.

* VEE 3.2 added a useful improvement to error handling. In previous versions of VEE, users who wanted to trap errors on objects through error pins simply got an error number, not an error message.

To get around this limitation, we added a new function named "errorInfo()" that allows a program to retrieve full details of the error. For example:


              +------------------+
              |      Formula     |
   +---+      +---+-----+--------+
   | 1 +----->| A | A/B | Result +--->
   +---+  +-->| B |     | error  +--+
          |   +---+-----+--------+  |          +--------------------------+
   +---+  |                         |          |        AlphaNumeric      |
   | 0 +--+                  +------+------+   +--------------------------+
   +---+                     | errorInfo() +-->| {511, "Divide/Mod by 0"} |
                             +-------------+   +--------------------------+
 
This example is also part of the file xerrdemo.vee. Of course, this file will not load in earlier versions of VEE.

* Beware of using error-handling as a standard practice, particularly with, say, a Transaction Object whose transactions contain complicated math formulas. VEE will allocate memory to parse these formulas, and if an error occurs during that parse activity, will lose that memory -- causing an incremental memory leak. This flaw is deeply rooted in the VEE architecture and will not likely disappear any time soon.

 TOP OF PAGE

[12.5] PROPAGATION PROBLEMS

* VEE propagation has certain idiosyncracies that can be difficult to puzzle out. A few examples can help illuminate such problems.

* A VEE user was tryin to build a record of three waveforms as follows:


                               +---------------+    +--------------------+
   +-----------+               | Demultiplexer |    |    Build Record    |
   | Function  |               +------+--------+    +---+------------+---+
   | Generator +-------------->| Data | Addr 0 +--->| A |   Output   |   |
   +-----------+               |      | Addr 1 +--->| B |   Shape:   | R +-->
                           +-->| Addr | Addr 2 +--->| C | [Array 1D] |   |
            +-----------+  |   +------+--------+    +---+------------+---+
            | For Range +--+
            |   (0:2)   |
            +-----------+
 
The "Build Record" object would never fire. This was a consequence of the way VEE loops work. Within a loop, input values are invalidated at the beginning of each loop, otherwise an object might generate an output based on previous rather than current values on its input pins.

Since the Build Record object only received one input on each iteration of the loop, only one input was valid at a time, and the object never fired.

After some more tinkering I came up with a solution using a "Shift Register" instead of a "Demultiplexer", where all three inputs would be valid simultaneously:


      +-----------+
      | For Range |
      |   (0:2)   +------------+
      +-----+-----+            |
            |                  |
            +------------------|-----------------------+ 
                               |                       |
                       +-------+--------+    +---------+----------+
      +-----------+    | Shift Register |    |    Build Record    |
      | Function  |    +------+---------+    +---+------------+---+
      | Generator +--->| Data | Current +--->| A |   Output   |   |
      +-----------+    |      | 1 Prev  +--->| B |   Shape:   | R +-->
                       |      | 2 Prev  +--->| C | [Array 1D] |   |
                       +------+---------+    +---+------------+---+
 
This program clocks three waveforms into the "Shift Register" and then strobes the "Build Record" to generate a record of them.

This could also be more simply done with a "Collector" if an array output is desired instead.

Another approach would be to use the original scheme, but embed the circuit that feeds the Build Record into a UserObject. The outputs of the UserObject will all be valid when it completes operation:


   +-------------------------------------------+
   |                 UserObject                |
   +---------------------------------------+---+
   |                   +---------------+   |   |    +--------------------+
   |  +-----------+    | Demultiplexer |   |   |    |    Build Record    |
   |  | Function  |    +------+--------+   |   |    +---+------------+---+
   |  | Generator +--->| Data | Addr 0 +-->| X +--->| A |   Output   |   |
   |  +-----------+    |      | Addr 1 +-->| Y +--->| B |   Shape:   | R +-->
   |                +->| Addr | Addr 2 +-->| Z +--->| C | [Array 1D] |   |
   |  +-----------+ |  +------+--------+   |   |    +---+------------+---+
   |  | For Range +-+                      |   |
   |  |   (0:2)   |                        |   |
   |  +-----------+                        |   |
   +---------------------------------------+---+
 
* Use of a Demultiplexer object inside a loop is a somewhat common source of confusion on VEE operation. We received a bug report on VEE that indicated a Formula box wasn't generating an output, even though its two input pins were receiving inputs.

This sounded like the same sort of problem: the Formula box was inside a loop and getting two more more values in different cycles. As the inputs were never valid in the same iteration of the loop, the Formula never fired.

The user's program showed this to be the case. The program, stripped down to essentials relevant to the problem at hand, looked like this:


   +--------------+
   | For Count: 4 +--+
   +--------------+  |
                     |
          +----------+
          |                                +-----+
          |   +------------------+     +-->|  0  |
          |   |  Demultiplexer   |     |   +-----+
          |   +------+---+-------+     |
          +-->| Data |   | Addr0 +-----+   +-----+
          |   |      |   | Addr1 +-------->|  1  |
          |   |      |   | Addr2 +-----+   +-----+
          +-->| Addr |   | Addr3 +--+  |
              +------+---+-------+  |  |   +-----+
                                    |  +-->|  2  |
                                    |  |   +-----+
                                    |  |
                                    |  |   +-----+
                                    +--|-->|  3  |
                                    |  |   +-----+
                                    |  |
                                    |  |   +-------------------+
                                    |  |   |      Formula      |
                                    |  |   +---+---------------+   +-----+
                                    |  +-->| A | A + B         +-->|     |
                                    +----->| B |               |   +-----+
                                           +---+---------------+
 
The Demultiplexer is driven by the For Count object to output a single value (0 through 3) for each cycle of the count. Since only one value is output per cycle, and the inputs to the Formula box are made invalid after each cycle, the two inputs A and B of the Formula box are never valid at the same time, and nothing happens.

This particular example makes it more clear why VEE invalidates inputs on each iteration of the loop.

This Formula box has two pins, A and B, and it simply adds the two values together, though the particular operation it performs is generally irrelevant for the purposes of this discussion.

Before the first execution of the loop, the two input pins have no values and are invalid:


   A:       *
   B:       *
   Result:  *
 
Suppose on the first iteration of the loop, the two pins are given the values 13 and 23. This gives:

   A:       13
   B:       23
   Result:  36
 
No problem so far. Now suppose on the next iteration of the loop, the two pins are given the values 17 and 50. This would presumably give:

   A:       17
   B:       50
   Result:  67
 
However, suppose that 17 is the first value sent to the Formula box and that the input pins haven't been rendered invalid after the first iteration. That means that until the second value, 50, is sent to the Formula box, the actual situation is:

   A:       17
   B:       23
   Result:  40
 
Since in this case, the Formula box fires the instant it gets the 17, the Formula box has generated a bogus output (40) and sent it out over its output line. This won't happen if the inputs were made invalid before beginning the loop, which is what VEE does in practice.

* In response to this circumstance, we are often asked to give the user more control over the behavior of the input pins, but in reality the issue is easy to deal with: just add memory elements to the program. This is as convenient a solution as any other that could be conceived.

Memory can be provided in some cases by a Shift Register, but variables are in general a straightforward way to accomplish most tasks. The example above can be modified to do the job as follows:


  +---+   +-----------------+
  | 0 +-->| Set Value: Nval |
  +---+   +--------+--------+
                   |
           +-------+-------+
           | For Count:  4 +--+
           +---------------+  |
                              |
         +--------------------+
         |                                +-----+
         |   +------------------+     +-->|  0  |
         |   |  Demultiplexer   |     |   +-----+
         |   +------+---+-------+     |
         +-->| Data |   | Addr0 +-----+   +-----+
         |   |      |   | Addr1 +-------->|  1  |
         |   |      |   | Addr2 +-----+   +-----+
         +-->| Addr |   | Addr3 +--+  |
             +------+---+-------+  |  |   +-----+
                                   |  +-->|  2  |
                                   |  |   +-----+
                                   |  |
                                   |  |   +-----+
                                   +--|-->|  3  |
                                   |  |   +-----+
                                   |  |
                                   |  |   +------------------+
                                   |  +-->| Set Value:  Nval |
                                   |      +------------------+
                                   |
                                   |      +-------------------+
                                   |      |      Formula      |
                                   |      +---+---------------+   +-----+
                                   +----->| A | A + Nval      +-->|  5  |
                                          +---+---------------+   +-----+
 
There's a few tricks to watch out for here. First, the global variable Nval is initialized as the first thing in the program. There's no necessary reason to do it in this particular program, as it will otherwise initialized before it is used, but it's a good programming practice.

Second, in this program Nval is always given a value before it is used in the Formula box. A VEE programmer needs to be sure that this is the case, or he or she will end up with a similar problem as that described for the not-invalidated input pins above.

* Miswired Timer objects can lead to very odd timing results, and are an excellent illustration of VEE propagation issues. For example, consider this simple program:


   +-----------+
   |           |
   |  Block 1  |
   |           |
   +-----+-----+
         |
         +--------+                 +--------------+
         |        |                 | AlphaNumeric |
   +-----+-----+  +-->+---------+   +--------------+
   |           |      |  Timer  +-->|              |
   |  Block 2  +--+-->+---------+   +--------------+
   |           |  |
   +-----------+  |
                  +-------------------+
                  |                   |
                  |   +-----------+   |  +-----------+
                  |   |           |   |  |           |
                  +-->|  Block 3  |   +->|  Block 4  |
                      |           |      |           |
                      +-----------+      +-----------+
 
The "Blocks" in this program are arbitrary VEE objects, UserFunctions, UserObjects, or whatever. The objective of the program is to time how long Block 2 takes to execute.

This program may actually work, but it isn't likely to. There are two problems. First, when the sequence-out pin of Block 1 fires, it will "ping" both Block 2 and the first input of the Timer. As the program does not deliberately specify which is pinged first, it can choose either. If it chooses Block 2 to ping first, it will not ping the Timer input until Block 2 is done, giving very misleading timing.

What can be confusing about this is that if you show VEE data flow, the data flow indicators may not indicate the actual sequence of operation. The sequence of operation may change depending on how the objects were wired together. Sometimes it will work, sometimes not.

The answer to this problem is to use a Do object to guarantee the proper sequence of operations:


      |
   +--+--+
   | Do  +--> do this first
   +--+--+
      |
   then this
 
The other problem is that the second input of the Timer is connected to the output pin of Block 2, and shares that wire with Block 3 and Block 4. There is no guarantee which of these will be executed first, and so the timing is very misleading.

It is best to connect the second input of the Timer to the sequence-out pin of Block 2. This way it will not be activated until Block 2 and all the blocks it is driving have completed. If there are other blocks connected to that sequence-out pin, a Do object should be used to ensure proper sequencing.

Here's the right way to build this program:


   +-----------+
   |           |
   |  Block 1  |
   |           |
   +-----+-----+
         |
      +--+--+
      | Do  +---------+
      +--+--+         |                 +--------------+
         |            |                 | AlphaNumeric |
   +-----+-----+      +-->+---------+   +--------------+
   |           |          |  Timer  +-->|              |
   |  Block 2  +--+   +-->+---------+   +--------------+
   |           |  |   |
   +-----+-----+  |   |
         |        |   |
	 +--------|---+
		  |
                  +-------------------+
                  |                   |
                  |   +-----------+   |  +-----------+
                  |   |           |   |  |           |
                  +-->|  Block 3  |   +->|  Block 4  |
                      |           |      |           |
                      +-----------+      +-----------+
 
 TOP OF PAGE
 LAST PAGE  BACK TO INDEX  NEXT PAGE