CSP for Java
(JCSP) 1.1-rc4

org.jcsp.awt
Class ActiveButtonControl

java.lang.Object
  extended by org.jcsp.awt.ActiveButtonControl
All Implemented Interfaces:
CSProcess

public class ActiveButtonControl
extends Object
implements CSProcess

This is a user-programmable finite state machine for controlling an array of ActiveButtons.

Process Diagram

Description

ActiveButtonControl is a user-programmable finite state machine for controlling an array of ActiveButtons. It is connected to the array by its event and configure channels, matching pairs of which must be attached to individual buttons. A button push generates a message down the attached event channel, which triggers a state transition in the ActiveButtonControl and a report that is sent down its report channel. The report consists of the new state just reached (an Integer) and, optionally, the channel index identifying which button was pushed (also an Integer) and the message generated by the button (the String that was labelling it). Also, the labels on all the buttons may be reset on entry to a new state, together with their enable/disable status (via messages sent back by ActiveButtonControl on its configure channels).

All external channels must be supplied as parameters to a constructor. The constructor must also be passed an array of String arrays (one String array defining the labels allowed for each attached button), the state table and a starting state.

The state table is an array of ActiveButtonStates. Each ActiveButtonState has three arrays, all of size equal to the number of buttons being controlled. The first array holds the indices defining the label to be displayed on each button when in that state. The second array holds the booleans defining the enable/disable status for each button for that state. The third array holds the states to change into if the corresponding button is pushed when in that state.

Channel Protocols

Input Channels
event[i] String The label on the attached ActiveButton (when it is pressed and released).
Output Channels
configure[i] String Defines the label on the attached ActiveButton.
Boolean Defines the enable/disable status on the attached ActiveButton.
report Integer The new state (after a state transition). Note: depending on the state transition table, this may be the same as the previous state..
Integer The channel index identifying which button caused the state transition. Note: this will be output after the above state information only if requested - see setReportButtonIndex.
String The label on the button that caused the state transition. Note: this will be output after the above information only if requested - see setReportButtonLabel.

Example

 import java.awt.*;
 import org.jcsp.lang.*;
 import org.jcsp.util.*;
 import org.jcsp.awt.*;
 
 public class ActiveButtonControlExample {
 
   public static void main (String argv[]) {
 
     final Frame root = new Frame ("ActiveButtonControl Example");
 
     final String[][] labels = {
       new String[] {"Hello World", "JCSP", "Restart"},
       new String[] {"Rocket Science", "JCSP", "occam"},
       new String[] {"Deadlock", "JCSP", "occam"},
       new String[] {"Race Hazard", "JCSP", "occam"},
       new String[] {"Starvation", "JCSP", "Quit", "Back"},
       new String[] {"Threads", "JCSP", "occam"},
       new String[] {"Livelock", "JCSP", "occam"},
       new String[] {"Monitors", "JCSP", "occam"},
       new String[] {"Alchemy", "JCSP", "Smile"}
     };
 
     final int nButtons = labels.length;
 
     final One2OneChannel[] fromButton = Channel.one2oneArray (nButtons, new OverWriteOldestBuffer (1));
     final Any2OneChannel[] toButton = Channel.any2oneArray (nButtons);
 
     final One2OneChannel report = Channel.one2one ();
 
     final ActiveButton[] button = new ActiveButton[nButtons];
     for (int i = 0; i < nButtons; i++) {
       button[i] = new ActiveButton (toButton[i].in (), fromButton[i].out (), "XXXXXXXXX");
       button[i].setBackground (Color.green);
     }
 
     root.setSize (450, 200);
     root.setLayout (new GridLayout (nButtons/3, 3));
     for (int i = 0; i < nButtons; i++) {
       root.add (button[i]);
     }
     root.setVisible (true);
 
     final int initial   = 0;                    // state names
     final int diagonal  = 1;
     final int opposite  = 2;
     final int centre    = 3;
     final int full      = 4;
     final int terminal  = 5;
 
     final String[] stateName = {
       "initial", "diagonal", "opposite", "centre", "full", "terminal"
     };
 
     final ActiveButtonState[] state = new ActiveButtonState[stateName.length];
 
     try {
 
       state[initial] =
         new ActiveButtonState (
           new int[] {
             0, 0, 1,
             0, 1, 1,                              // label index
             1, 1, 1
           },
           new boolean[] {
             true,  true,  false,
             true,  false, false,                  // enable/disable
             false, false, false
           },
           new int[] {
             diagonal, initial,  initial,
             initial,  initial,  initial,          // next state
             initial,  initial,  initial
           }
         );
 
[In this example, nine buttons are laid out in a 3x3 grid in the root frame. The layout of the above state definition reflects this grid. Note that this code is enclosed within a try-catch block since the ActiveButtonState constructor performs numerous consistency checks on its parameters and may throw an exception.

The label index array specifies that, in this initial state, the north-west button and its east and south neighbours display their 0-index labels (i.e. "Hello World", "Rocket Science" and "Race Hazard" respectively). All the other buttons display their 1-index labels (which all happen to be "JCSP").

The enable/disable array specifies that, in this initial state, all those buttons displaying "JCSP" are disabled and all the others are enabled.

The next state array specifies that, in this initial state, if the top-left button is pushed, then the state should change to diagonal. However, if any other button is pushed, the state remains as initial. Note that it doesn't actually matter what is defined for those buttons that are disabled in this state.

The diagonal, opposite, centre and full states are defined similarly. We pick up the program for the definition of its terminal state (where all the labels are "JCSP" and all the buttons are disabled).]

       state[terminal] =
         new ActiveButtonState (
           new int[] {
             1, 1, 1,
             1, 1, 1,                              // label index
             1, 1, 1
           },
           new boolean[] {
             false, false, false,
             false, false, false,                  // enable/disable
             false, false, false
           },
           new int[] {
             terminal, terminal, terminal,
             terminal, terminal, terminal,         // next state
             terminal, terminal, terminal
           }
         );
 
     } catch (ActiveButtonState.BadArguments e) {
 
      System.out.println (e);
      System.exit (0);
 
     };
 
     new Parallel (
       new CSProcess[] {
         new Parallel (button),
         new CSProcess () {
           public void run () {
             final ActiveButtonControl control;
             try {
               control = new ActiveButtonControl (
                 fromButton.in (), toButton.out (), report.out (), labels, state, initial
               );
               control.setReportButtonIndex (true);
               control.setReportButtonLabel (true);
               control.run ();
             } catch (ActiveButtonControl.BadArguments e) {
               System.out.println (e);
               System.exit (0);
             }
           }
         },
         new CSProcess () {
           public void run () {
             boolean running = true;
             while (running) {
               final int newState = ((Integer) report.in ().read ()).intValue ();
               final int buttonIndex = ((Integer) report.in ().read ()).intValue ();
               final String buttonString = (String) report.in ().read ();
               System.out.println (
                 "Button " + buttonIndex +
                 " (" + buttonString + ") pressed ==> " + stateName[newState]
               );
               running = (newState != terminal);
             }
             final CSTimer tim = new CSTimer ();        // countdown to exit
             final long interval = 1000;            // one second
             long timeout = tim.read ();
             for (int i = 10; i >= 0; i--) {
               timeout += interval;
               tim.after (timeout);
               final String iString = (new Integer (i)).toString ();
               for (int j = 0; j < nButtons; j++) {
                 toButton[j].write (iString);
               }
             }
             root.setVisible (false);
             System.exit (0);
           }
         }
       }
     ).run ();
 
   }
 
 }
 
The countdown to exit sequence is just for fun. In its terminal state, this ActiveButtonControl disables all its buttons and will never change state again. This leaves the buttons free to be configured by some other process, such as the last one above once it has detected that the controller is dead. This is why the toButton configure channels were created as Any2OneChannelImpl, rather than the more usual One2OneChannelImpl.

Author:
P.H. Welch
See Also:
ActiveButton, ActiveButtonState

Nested Class Summary
static class ActiveButtonControl.BadArguments
          This gets thrown if a consistency check fails in the ActiveButtonControl constructor.
 
Constructor Summary
ActiveButtonControl(AltingChannelInput[] event, ChannelOutput[] configure, ChannelOutput report, String[][] label, ActiveButtonState[] state, int startState)
          Constructs a new ActiveButtonControl, performing consistency checks on its supplied arguments.
ActiveButtonControl(AltingChannelInput[] event, ChannelOutput[] configure, ChannelOutput report, String[][] label, ActiveButtonState[] state, int startState, boolean verbose)
          Constructs a new ActiveButtonControl, performing consistency checks on its supplied arguments, with a verbose reporting option.
 
Method Summary
 void run()
          Main body of the process.
 void setReportButtonIndex(boolean condition)
          Defines whether the index of the pushed button causing a state transition should be included in the report.
 void setReportButtonLabel(boolean condition)
          Defines whether the label on the pushed button causing a state transition should be included in the report.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

ActiveButtonControl

public ActiveButtonControl(AltingChannelInput[] event,
                           ChannelOutput[] configure,
                           ChannelOutput report,
                           String[][] label,
                           ActiveButtonState[] state,
                           int startState)
                    throws ActiveButtonControl.BadArguments
Constructs a new ActiveButtonControl, performing consistency checks on its supplied arguments.

Parameters:
event - equal-indexed elements of event and configure must be connected to the same ActiveButton.
configure - equal-indexed elements of event and configure must be connected to the same ActiveButton.
report - the channel on which state transitions are reported. A report has up to three messages: the new state, the index of the button triggering the transition (optional) and its label (optional).
label - an array of string arrays (one for each controlled botton). Each string array defines the label set allowed for each button.
state - the state transition table.
startState - the starting state for this finite state machine.
Throws:
ActiveButtonControl.BadArguments - if the consistency check fails. The exception contains details of the error.

ActiveButtonControl

public ActiveButtonControl(AltingChannelInput[] event,
                           ChannelOutput[] configure,
                           ChannelOutput report,
                           String[][] label,
                           ActiveButtonState[] state,
                           int startState,
                           boolean verbose)
                    throws ActiveButtonControl.BadArguments
Constructs a new ActiveButtonControl, performing consistency checks on its supplied arguments, with a verbose reporting option.

Parameters:
event - equal-indexed elements of event and configure must be connected to the same ActiveButton.
configure - equal-indexed elements of event and configure must be connected to the same ActiveButton.
report - the channel on which state transitions are reported. A report has up to three messages: the new state, the index of the button triggering the transition (optional) and its label (optional).
label - an array of string arrays (one for each controlled botton). Each string array defines the label set allowed for each button.
state - the state transition table.
startState - the starting state for this finite state machine.
verbose - if true, a running commentary is printed on the consistency checks and state transitions as they occur.
Throws:
ActiveButtonControl.BadArguments - if the consistency check fails. The exception contains details of the error.
Method Detail

setReportButtonIndex

public void setReportButtonIndex(boolean condition)
Defines whether the index of the pushed button causing a state transition should be included in the report. The default is that it should not be reported.

Parameters:
condition - if true, the button index is reported - otherwise it is not reported.

setReportButtonLabel

public void setReportButtonLabel(boolean condition)
Defines whether the label on the pushed button causing a state transition should be included in the report. The default is that it should not be reported.

Parameters:
condition - if true, the button label is reported - otherwise it is not reported.

run

public void run()
Main body of the process.

Specified by:
run in interface CSProcess

CSP for Java
(JCSP) 1.1-rc4

Submit a bug or feature to jcsp-team@kent.ac.uk
Version 1.1-rc4 of the JCSP API Specification (Copyright 1997-2008 P.D.Austin and P.H.Welch - All Rights Reserved)
Java is a trademark or registered trademark of Sun Microsystems, Inc. in the US and other countries.