Here we describe a program to connect over the serial line to a
device that sends a temperature reading. In Chapter 24: Javelin Demo 1 we will
describe in detail this Java powered device that does the temperature
measurements. Here we just assume that there is a device at the
other end of the serial line that understands our protocol for requesting
the temperature value.
The program uses the classes and methods discussed
in the previous sections for communications
over the serial port. The program illustrates how you might use
a Java program to obtain data from any device via a serial line.
The program will also work with the client/server
system discussed in Chapter 14 and so illustrate a complete
system for access to data from a remote device over the Internet.
We have programmed the external device to follow
a simple protocol for obtaining its data. This protocol requires
that the application on the desktop (or whatever platform with JVM
and javax.comm) first sends a password (actually a
two byte numerical value) to the device. If this is accepted, the
device program will send a two byte integer data value for the temperature
in units of 0.5 degrees Celsius.
The desktop (or any platform that can handle
J2SE and javax.comm) program consists of two primary classes:
- GetJavelinData
is in charge of the sending and receiving data over the serial
port with the device (a Javelin Stamp board discussed in Chapter
23). This class implements the Runnable
interface and its run()
method contains a loop that first sends the password and then
reads the value sent to it from the sensor. It converts each byte
pair received into a 4-byte int
value using the byte array to primitive types techniques discussed
in Chapter 9. Before repeating the data read operation, the loop
pauses for a period whose length is passed via the constructor
parameter.
- SerialToJavelin
provides a graphical user interface with a dropdown menu on the
menu bar that lists the serial ports on the platform. Selecting
one of these will cause the program to attempt to open the port.
If it succeeds, it passes the port s SerialPort object to an
instance of GetJavelinData. Hitting
the Go button will invoke the start() method in the GetJavelinData object, which
will begin its data taking loop. Hitting Stop will invoke
the stop method in that object. A text area displays the temperature
values, which are printed from the GetJavelinData loop via
print methods of the Outputable interface. A file menu provides
for saving this data to a file.
The complete code listings for these two classes
can be found on the following
page.
When the program SerialToJavelin first begins,
it builds a menu with the names of the serial ports on the platform.
It invokes the method getPorts(), shown below, which
uses the CommPortIdentifier
static method getPortIdentifiers()
to obtain the CommPortIdentifier
object for each port on the platform. The serial types of ports
are saved in an instance of Hashtable.
The getPorts()
method in SerialToJavelin |
/**
* Use the CommPortIdentifier
static method to obtain a list of
* ports on the platform.
Pick out the serial ports from the
* list and save in a Hash
table. Use the port names as keys.
**/
static void getPorts () {
// First get the list of ports on
this platform
Enumeration port_list = CommPortIdentifier.getPortIdentifiers
();
// Scan through the list and get the
serial ports
while (port_list.hasMoreElements ()) {
CommPortIdentifier port_id
=
(CommPortIdentifier)port_list.nextElement
();
if (port_id.getPortType
() == CommPortIdentifier.PORT_SERIAL) {
fNumSerialPorts__++;
fSerialTable__.put
(port_id.getName (), port_id);
}
}
} // getPorts |
When the user selects a serial port from the menu the actionPerformed()
method is invoked. The following code shows the actions taken to
open the port.
The actionPerformed()
method in SerialToJavelin |
public
void actionPerformed ( ActionEvent e ) {
boolean status = false;
String command = e.getActionCommand
();
if (command.equals ("Go"))
{
...
tests and actions for other commands ...
}
// Scan the serial ports names to
look for a match
// to the menu items.
Enumeration enum_ports = fSerialTable__.keys
();
while (enum_ports.hasMoreElements
()) {
String port_name = (String)enum_ports.nextElement
();
if (command.equals (port_name)
) {
fSelectedPortID__
=
(CommPortIdentifier)fSerialTable__.get (port_name);
if (fCurrentPort__
!= null) fCurrentPort__.close ();
//
Open port Allow for 20 seconds block
try
{
fCurrentPort__
=
(SerialPort)fSelectedPortID__.open
(
"Serial to Javelin",20000);
}
catch
(PortInUseException pie) {
println
("Error: Port in use");
fCurrentPort__
= null;
fSelectedPortID__
= null;
return;
}
//
set up the serial port
try
{
fCurrentPort__.setSerialPortParams
(
BAUD_RATE,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
}
catch
(UnsupportedCommOperationException uce) {
//
This error shouldn't happen
}
try
{
getStreams
();
}
catch
(IOException ioe) {
println
("Error: Cannot open streams to port");
fCurrentPortLabel.setText
("No Port Open");
fCurrentPort__.close
();
return;
}
fCurrentPortLabel.setText
(port_name);
fGetJavelinData.setStreams
(fPortInStream,fPortOutStream);
fGoButton.setEnabled
(true);
}
}
} // actionPerformed () |
The code first looks for a match to the port
name. It then attempts to open the port. If it succeeds it sets
the serial port parameters to a baud rate of 9600, eight data bits,
one stop bit, and no parity. The serial line device (a Javelin Stamp
evaluation card in this case) must, of course, use the same settings.
The input and output streams for the serial
port are then obtained. The input stream is wrapped as a DataInputStream and the
Output stream is wrapped with a PrintStream.
void getStreams() throws IOException {
portInStream =
new DataInputStream(currentPort.getInputStream());
portOutStream =
new PrintStream(currentPort.getOutputStream(),
true);
}
When the user hits the Go
button, the actionPerformed()
method is invoked again and the code section for the Go
command invokes the start()
method in the GetJavelinData,
which is shown on the following
page.
The parameters in the constructor,
GetJavelinData(Outputable
parent, int rate)
include a reference to the Outputable
parent that will be used for callbacks to the
instance of SerialToJavelin.
This class implements the interface by overriding its print(String)
and println(String)
methods with ones that place strings on the text area in the user
interface. The rate parameter determines how often the data value
from the device is read.
The data from the sensor arrive over the serial
port as a sequence of bytes. Each pair of bytes must be converted
to an int primitive value. We
use the techniques described in Chapter 9 in which a byte array
becomes the source for a ByteArrayInputStream,
which in turn is wrapped with a DataInputStream
class. The latter class offers the readInt()
method that will return an int value with the data
bytes in the lower 2 bytes of the 4 byte value.
Note that the programs in the desktop and in
the device follow Java's standard big
endian format in which the bytes arrive in order of the highest
order byte first and the lowest order byte last. [Since in big endian
the highest order byte is in the lowest address and the lowest order
byte is the highest address. Sending the data would start at the
low end of the memory address, e.g. an array, and work upward.]
The loop in the run()
method first sends the password, which here consists of just a two
byte value that will match a value set in the device program. If
the password is not accepted, the thread processing stops. Otherwise,
the raw data value is read. Then a calibration is done, which
here simply consists of a slope and offset correction. (The data
is generated in units of 0.5 degrees Celsius.) The Outputable
reference provides for a callback to the user interface to print
the temperature value.
Though many improvements and custom features
can be added, this program illustrates all the essentials of communicating
over the serial line with a device such as a sensor to obtain data
of interest. In Chapter 23 we will show how to set up the other
end of the line with a device that illustrates the application of
embedded Java processors.
References and Web Resources
Latest update: Dec. 13, 2004
|