Friday, January 2, 2009

Efficient Programs and Button Listeners

In my blog on January 1st, I explained how the RConsole class can be used to easily send output from the NXT brick over a Bluetooth connection to your PC. However, the program has a deficiency. The escape button must be pressed and held for the program to stop.

True, the while loop is terminated whenever the brick’s escape button is pressed. But, after reading the raw and processed values of the Electro Optical Proximity Detector (EOPD) and printlning those results to the RConsole, the loop pauses for five seconds. This pausing means that the escape button’s state is checked approximately once every five seconds at the top of the while loop.

So, to stop the program, the user has to press and hold down the escape button until the while loop has an opportunity to read the button’s state. Pressing and releasing the escape button is insufficient. If the escape button is in the released position when the while loop checks the button’s state, the while loop will execute again even though the button might have been pressed and released when the loop was paused.

This problem is best solved by using the ButtonListener interface. The interface has two methods: buttonPressed(Button b) and buttonReleased(Button b). Once a button has been registered with a listener, these methods fire whenever the button is pressed or released, as the case may be. Furthermore, these methods fire regardless of what other things the program might be currently doing.

In the new version of the program, given at the end of this blog entry, the while loop is now controlled by a boolean variable, keepItRunning. The variable is initialized to true. The program implements the buttonPressed method such that it changes the keepItRunning variable to false. Although we are not explicitly using the buttonReleased method, we are obliged to implement it because it is part of the ButtonListener interface. So, we give the buttonReleased method an empty implementation.

The program line Button.ESCAPE.addButtonListener(this); registers the escape button with a listener. The this keyword indicates that the buttonPressed and buttonReleased methods are implemented in this class. (It is possible for the methods to be in another class; so, the addButtonListener method must know where these methods can be found.)

To try this new idea out, upload this program, as given below, to your NXT and start it running. Now, get your nxjconsole running from a command prompt. The program works in exactly the same way as described in my January 1st post. However, if the escape button is pressed and released, the program will end after its five-second pause. The program ends because the pressing of the escape button fires an event, which in turn calls the buttonPressed method. That method changes the keepItRunning boolean variable from true to false. The while loop ends because the while loop will only run as long as keepItRunning is true.

What follows next is the code for EOPDSensor2:

import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.SensorPort;
import lejos.nxt.comm.*;
import lejos.nxt.addon.*;
import lejos.nxt.*;

public class EOPDSensor2 implements ButtonListener{

private boolean keepItRunning = true;

public void buttonPressed(Button b){
keepItRunning = false;
}

public void buttonReleased(Button b){}

public void runProgram(){

Button.ESCAPE.addButtonListener(this);

RConsole.openBluetooth(40000);

LCD.drawString("Connected", 0, 2);

EOPD electroSensor = new EOPD(SensorPort.S1);

while(keepItRunning){
electroSensor.setModeLong();
RConsole.println(Integer.toString(
electroSensor.readRawValue()));
RConsole.println(Integer.toString(
electroSensor.processedValue()));

try{
Thread.sleep(5000);
}catch(InterruptedException e){
System.exit(0);
}
}

RConsole.println("Closing...");

RConsole.close();
}

public static void main(String[] args){
EOPDSensor2 programInstance = new EOPDSensor2();
programInstance.runProgram();
}
}

No comments: