|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 7 of 7
So now assume that we could access the correct interface and open the serial port. The question now is: How do you set baud rate and parity? You can use native methods until the Java VM supports device drivers.
The following steps can be used to build an application in Java that wishes to use some of the abilities of the underlying operating system that are not directly available to the Java VM. We are only going to cover the points that are germane to the serial port interface we are going to build.
javah -jni "classname", open the h file in an editor, and copy and paste the signature definitions from the .h file to your C file.In Unix, run:
In Windows 95/NT, run:
Whenever you implement a native method interface, it is important that you try to reuse existing classes. Serial devices present
us with a pretty clear-cut choice for determining what existing classes might be of help. Because we want to write and read
to streams, we should model the output to look like a stream. Therefore, it would make sense for us to use the Java classes
that implement stream interfaces. Specifically, we're going to extend Java.ion.InputStream and Java.io.OutputStream.
Luckily for us, these classes were originally designed in quite a clever fashion; you need only replace a few methods to reuse
all of the existing code. So with very little work on our part, we have SerialInputStream.java and SerialOutputStream.java. Both of these new classes require that the constructor have a PlainSerial object. The PlainSerial class provides the interface, which we'll call the Serial Device interface. The Serial Device interface has been abstracted
for all serial devices supporting the basic read and write of single bytes, with no time or pacing requirements. Serial devices
can have very demanding requirements, which are found most often in real-time environments. For example, some serial lines
my require paced output or rapid response within given and predictable time frames. (The Resources section of this article provides several links to articles that discuss real-time issues with Java.)
As you might expect, we need to implement open, close, read, and write methods for the PlainSerial class. The SerialInputStream and SerialOutputStream classes use the native methods shown next by calling the appropriate method.
public class PlainSerial {
public int openResult = -1;
private final native int OpenDevice( String device, int baud);
private native void writeAByte( int theFd, int theByte);
private final native int readAByte( int theFd );
private final native void close( int theFd );
public void write( int b ) {
writeAByte( openResult, b);
}
public void close() {
close(openResult);
}
public int read( ) {
return ( readAByte( openResult ) );
}
/**
* Open the device by name at the requested baud rate
*/
public PlainSerial(String device, int baud) throws IOException {
System.out.println("About to call open");
openResult = OpenDevice(device, baud);
System.out.println("Open result:" + openResult );
if ( openResult < 0 ) {
switch (openResult) {
default:
throw new IOException("Error Opening Device " + openResult);
}
}
}
}
Note that the JNI requires the signatures of the native methods to match the name of the calling class and package. For this
reason, you see PlainSerial twice in the signature. The C code does the actual interfacing to the underlying operating system's serial file. The following
code segment demonstrates the method signatures required to interface PlainSerial to the underlying operating system.
/**
* The descriptor for the device is returned, if the
* device can be opened. If it cannot then a -1 error
* is returned.
* Class: Java_commerce_PlainSerial_PlainSerial
* Method: OpenDevice
* Signature: (Ljava/lang/String;I)I
*/
JNIEXPORT jint JNICALL Java_Java_commerce_PlainSerial_PlainSerial_OpenDevice
(JNIEnv *env , jobject obj, jstring tty, jint lBaud) {
/*
* Write a single byte
* Class: Java_commerce_PlainSerial_PlainSerial
* Method: writeAByte
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_Java_commerce_PlainSerial_PlainSerial_writeAByte
(JNIEnv *env, jobject obj, jint theFd, jint theByte) {
/*
* Read a single byte
* Class: Java_commerce_PlainSerial_PlainSerial
* Method: readAByte
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_Java_commerce_PlainSerial_PlainSerial_readAByte
(JNIEnv *env, jobject obj, jint theFd) {
Complete the interface to the operating system using the following guidelines:
open and ioctl calls.CreateFile methods with SetCommState described in the Windows 95/NT answerbooks for the IDE you are using.
Beyond time-out
Because serial devices often do not respond (either they're not connected, not turned on, or something else is plugged in
into the port), time-out support alone is not enough. To address this situation head on, I have also incorporated a bounded
buffer, which provides the ability to read with a maximum limit on the wait time. Although I could have implemented this buffer
by using the underlying operating system, I chose not to because that functionality can be performed in Java.
Much of the design and implementation for SynchronizedBuffer comes from Concurrent Programming in Java -- Design Principles and Patterns by Doug Lea. Here's how it works: A thread (producer) continuously reads the input device and when characters arrive they
are given to the SynchonizedBuffer object using synchronized buffers to implement controlled access. We can't have the producer (the thread getting the bytes
from the serial port) and the consumer (the application requesting the data) updating the counters at the same time. We also
use wait and notify so that the consumer is informed whenever there is data from the producer. Be sure to thoroughly examine SynchronizedBuffer.java, SerialInputStreamThreaded.java, and SerialThreadReader.java for all the details. You can view the entire serial package here.
This article lays the foundation for my upcoming smart card series. In order to use smart cards, you need to talk to them, and one of the cheaper ways of talking to them is with a serial card reader; thus, the need for serial device support. This series of articles will cover the techniques for using a smart card with your applications. We'll work closely with the Java Electronic Commerce Framework (JECF), which I will use as the foundation layer for the examples we'll build.
Read more about Core Java in JavaWorld's Core Java section.