OCW Language and Interpreter

OCW Language and Interpreter v1.00 coming soon!
Will Grover
wgrover@users.sourceforge.net
This page: http://ocw.sourceforge.net
OCW project page: http://sourceforge.net/projects/ocw
My home page: http://www.ocf.berkeley.edu/~wgrover/
Revised: June 17, 2004


Introduction to the OCW language and interpreter

The OCW language is a script-based language for controlling and coordinating complex operations in microfluidic valves and pumps, although it could be used to control any automation project that uses TTL level inputs. The OCW interpreter was written in Perl and uses common, inexpensive parallel ports to provide TTL control of the circuits that actuate microfluidic valves and pumps. Collectively, OCW was designed with a few goals in mind:

  • Few commands. Not many more than the three that give the language its name: open a valve, close a valve, and wait for a time.
  • User-declared subroutines. Common, logical operations like "close all valves" or "pump fluid" or "shut down" are declared once and then called elsewhere as a subroutine.
  • Short OCW programs do complex things. The main part of a program is mostly a list of subroutines. These programs can be understood and edited at a glance.
  • Operator intervention. Messages in the program can be passed to the program operator at runtime. The operator can control aspects of program execution at runtime as well.
  • Inexpensive, common hardware. Practically all PCs have a parallel port. Each parallel port can be used by OCW to control up to eight TTL lines for use in microfluidic device control or any other imaginable automation project. If you need more than eight digital control lines, inexpensive ISA or PCI cards can be used to add as many parallel ports as necessary.
  • A tiny and portible interpreter. The OCW interpreter is about one page of Perl. It should be able to run on any computer that can run Perl. Each OS deals with parallel ports differently, and these differences are handled by tiny OS-specific helper programs written in C.

    OCW Installation and Usage

    Currently Linux is known to be supported and Windows/Cygwin support is in the works. To install, simply grab the source, uncompress, and run

  • make
  • to make everything, optionally become root and run

  • make install
  • to install the ocw program, then use your favorite text editor to write your own OCW program (unarmed for now; see below) and run

  • ocw myprogram.ocw
  • where myprogram.ocw is the name of your OCW program. When you are ready to run your program and actually control parallel ports, add the armed keyword to the preamble of your OCW program, become root (see below for reasons), and run your OCW program as shown above.


    OCW language commands and syntax

    All OCW programs must have a few fundamental components. This includes a main function that starts with main and ends with end, and at least one parallel port address assignment function a appearing in the preable (the region before the main function). You'll probably want at least a few o, c, and w commands if you want the program to actually do anything!
    OCW command: Command definition: Additional comments:
    on Open valve n Available valve numbers are 0 through 8n-1 where n is the number of parallel ports available on the system. Valves 0 through 7 are assigned to the first port address set, valves 8 through 15 are assigned to the second port address set, and so on (see the a command below). If the valve is already open, it will remain open.
    cn Close valve n Available valve numbers are the same as for the o command. If the valve is already closed, it will remain closed.
    wt Wait t milliseconds. The overall accuracy and precision of the wait command is system dependent. If a wait shorter than the minimum possible wait is specified, the program will still wait for the minimum possible wait without any obvious errors.
    /comment Comment line If a / is placed at the beginning of a line, all remaining text on that line is ignored. In addition, comments within functions (either main or a subfunction) are printed on the screen during execution. Place a comment before a stop command to tell the operator exactly what to do during that stop.
    stop Stop program execution until user presses ENTER. Any comments preceeding the stop command will be printed on the screen while the system awaits user input. Note that using the ENTER key to exit a stop command is different from using ENTER to escape a repeating function call.
    main Begin main function Every program must have a main function; programs lacking a main function won't do anything. The main function cannot be repeated arbitrarially like subfunctions can. If find that you need to repeat the entire main function, place the contents of the main function in a subfunction and call that subfunction using repeats as necessary (see call below).
    end End main program or a subfunction The main function and all subfunctions are each terminated by an 'end' command. The code lying between main and the main function's end is the main function; code between a subfunctions declaration (see below) and that subfunction's end is that subfunction's code.
    sub Begin the definition of the subfunction named sub. Any line containing a single word that isn't another OCW function is assumed to be the declaration of a subfunction. The name of the subfunction marks the beginning of the subfunction's code, and the end command marks the end of the code.
    call sub n Call subfunction sub n times, once if n is omitted. When a subfunction is called, its code is executed as if the subfunction's code was actually inserted in the program at the call command. Adding an integer number n after the function name in the call command will repeat that subfunction's code n times; if the number is omitted the code is executed once. It is possible to call (or actually recall) the main function as a subfunction (call main), or to call a subfunction from within that subfunction, or to have loops of subroutines that call each other if necessary; programs using these constructs will run forever and must be aborted using CTRL + C. Finally, by specifying a large repeat number and pressing ENTER at runtime to exit the loop, elements of OCW programs can be controlled at runtime by the operator. See the "OCW interpreter commands" below for more information.
    an Preamble command to set parallel port address to n The a command is called as many times as there are parallel ports for use on your computer. The order in which the ports are called is used to determine which set of 8 valves are assigned to which parallel port. For example, the first parallel port address set using a will control valves 0 through 7, the second port address set with a will control valves 8 through 15, and so on for as many ports as you have. Currently, the port address must be set using a decimal number, even though we usually refer to these addresses using hexidecimal numbers. I'll fix this eventually, but for now some common parallel port hex addresses and their decimal equivalents are shown in the "Addional application notes" section below.
    armed Preamble command to activate parallel ports OCW code without an armed command somewhere in the preamble will run without actually doing anything with the parallel ports. This corresponds to a "safety" or "debug" mode in which the program can be run without root priveleges and without worrying about writing to incorrect memory addresses. Using this feature, OCW programs can be written and debugged on one PC before transferring the program to the actual valve control PC. When ready to actually run the program, include the armed command in the preamble and become root, then run the program.
    negate Preamble command to negate parallel port logic In ordinary operation, the OCW program assumes that opening a valve corresponds to energizing a solenoid valve (sending out a "high" or "1" TTL voltage) and closing a valve corresponds to de-energizing a solenoid valve (sending out a "low" or "0" TTL voltage. Depending on the type of solenoid valve used and the construction of the system, this assumption may need to be reversed. When the negate command is called once in the preamble of an OCW program, an open valve corresponds to the de-energized state of the solenoid valve and a closed valve corresponds to the energized state.


    OCW interpreter commands:

    A few commands may be issued while the OCW interpreter is running. These commands mostly affect the execution and flow of the OCW program being run.
    OCW command: Command definition: Additional comments:
    ENTER Continue execution (after a stop command has halted program execution) Pressing ENTER during a repeating subfunction call serves a very different purpose; see below.
    ENTER Escape the current repeating subfunction This feature can be used to create "repeat until interrupted" functions in an OCW program. To use, include a call function with a huge repeat number like 1000000. When the code is run, the called subfunction will be repeated until the user presses ENTER (or a million repeats, whichever comes first). This turns out to be very useful in situations in which the exact number of actions required isn't known but will be determined by the operator at runtime.
    CTRL + C Quit current running program Just the old classic way to quit a program. Of course, if the interpreter reaches the end of the OCW code being run, then the program will quit by itself.

    Sample OCW programs:

    The inevitable and obligatory "hello world" program:

    main
    /hello world
    end
    

    A slightly more complex program that simultaneously opens four even-numbered valves and closes four odd-numbered valves. The parallel port used by the program has hex address 0x378 (decimal equivalent 888). The command a888 sets the address of the port to use for controlling the three valves, and the armed command makes the program actually control the port:

    a888
    armed
    main
    /open the even-numbered valves:
    o0
    o2
    o4
    o6
    /close the odd-numbered valves:
    c1
    c3
    c5
    c7
    end
    

    A full program for controlling microfluidic diaphragm pumps as described in Grover et al., Sensors and Actuators B 89, 3, 2003. The program uses one parallel port to control three logical lines which in turn are used to switch three solenoid valves. These valves control the flow of pressure or vacuum to the three monolithic membrane valves that form the diaphragm pump. The pump is actuated 100 times (perhaps pumping about 1 microliter in the process) before a graceful shutdown of the device.

    The main function has four steps. First, a subfunction named close_all_valves is called once. A helpful note for the operator is printed on the screen—"Add buffer to the reservoir"—and program execution stops until the user presses ENTER. Next a subfunction named pump_forward is called 100 times. Finally the close_all_valves subfunction is called again, then the program ends.

    The remainder of the code consists of definitions of the subfunctions used in the main function. The close_all_valves subfunction contains three c commands to close all three valves. The pump_forward subfunction contains the six o and c steps necessary for driving the diaphragm pump through a single cycle, interspersed with calls to an additional subfunction, pump_wait, that provides a constant 100 millisecond wait time for each of the six steps:

    /Sample OCW program by Will Grover
    
    a888
    armed
    
    main
    call close_all_valves
    /Add buffer to the reservoir
    stop
    call pump_forward 100
    call close_all_valves
    end
    
    close_all_valves
    c0
    c1
    c2
    end
    
    pump_forward
    o0
    call pump_wait
    c2
    call pump_wait
    o1
    call pump_wait
    c0
    call pump_wait
    o2
    call pump_wait
    c1
    call pump_wait
    end
    
    pump_wait
    w100
    end

    Notice that the entire device operation is described in the five lines of the main function. Once a few useful subfunctions have been designed, the main part of the program can become quite readable and easy to edit. Simple subfunctions can also be treated like variables that are referred to elsewhere in the program. Editing the single w function in pump_wait is much quicker than changing six individual w commands in the pump_forward subfunction.

    OS-specific notes

    Information about porting OCW to different operating systems:
    Operating System: Supported? Make command: Notes:
    Linux Yes make linux Uses the linux.c helper program, which in turn uses the Linux-specific commands ioperm() and outb(). These commands require root permissions to run without causing a segmentation fault, so you need to be root before you can run an armed OCW program on a Linux system. I hope to change this in a future version...
    Windows (Cygwin) Under development Under development Under development


    Additional application notes:

    Guide for wiring digital lines to the Centronics male end of a standard IEEE-1284 printer cable:
           0 1 2 3 4 5 6 7   G G
           | | | | | | | |   | |
           v v v v v v v v   v v
     ___________________________________________
    \    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _    /
     \                                         /
      \  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  /
       \_____________________________________/
    
           ^ ^ ^ ^ ^ ^ ^ ^
           | | | | | | | | 
           G G G G G G G G
    
    This is the end of the cable that usually connects to a printer; the other end is also male but has pins and connects to the parallel port on a PC. If this cable is attached to the first port address set in an OCW program (see the a command above), valves 0 through 7 will be controlled by this cable. The second and subsequent port addresses declared will control valves 8 through 15, 16 through 23, and so on. Conductors marked "G" are grounded and should all be connected with the signal ground on the circuit being controlled by the TTL lines.

    Common parallel port hex addresses and their decimal equivalents for use in a commands:
    Hex address: Decimal address:
    0x3BC 956
    0x378 888
    0x278 632
    0x368 872
    0x268 616
    0x358 856
    0x258 600


    The OCW language and interpreter are (c) 2003 by Will Grover (wgrover@users.sourceforge.net). Both are released under the GNU General Public License.

    SourceForge.net Logo