Abriendo nuevos puertos a Java con javax.comm

Me presentaron el paquete de clases javax.comm cuando descubrí que se usaban en el kit de desarrollo para Java Ring. (Para obtener detalles sobre javax.comm, consulte la columna Java Developer de Rinaldo Di Giorgio en la edición de mayo de JavaWorld: "Java obtiene soporte en serie con el nuevo paquete javax.comm.") Durante mi loca carrera por JavaOne para conseguir un programa en mi anillo, me encontré con una variedad de problemas, entre los que destacaba la comunicación con el anillo. Descargué la distribución de Java Developer Connection e intenté sin éxito usarla para hablar con Java Ring. Más tarde, descubrí el problema con mi anillo: no tenía las API heredadas de Dallas Semiconductor instaladas correctamente. Con el anillo funcionando, básicamente me olvidé del paquete de comunicaciones. Es decir, hasta un fin de semana hace aproximadamente un mes, que es el punto de partida de esta historia.

Por muchas razones diferentes (principalmente relacionadas con entornos simulados altamente interactivos, por ejemplo, juegos), la computadora principal de mi "laboratorio" ejecuta Windows 95. Sin embargo, en este fin de semana en particular, estaba más preocupado por otra computadora que, en De muchas maneras, era tan poderoso como el Java Ring: un PDP-8 / e de Digital Equipment Corporation.

El PDP-8 fue posiblemente la primera computadora personal verdadera. Diseñado a fines de la década de 1960 y producido en cantidades relativamente altas en la de 1970, el PDP-8 podía ser levantado por una sola persona, funcionaba con una corriente de línea de 120 voltios y costaba menos de 0,000. La mayoría de estas computadoras se envían con un solo periférico: un terminal modelo de teletipo ASR-33, el "TTY" original en la jerga informática.

El teletipo ASR-33 era un terminal de impresión que venía con un lector de cinta de papel y un punzón. Sí, era cinta de papel, papel de 1 "de ancho con agujeros perforados, que era el medio de almacenamiento principal para los programas en el PDP-8.

El PDP-8 fue la primera computadora que programé y, por lo tanto, tiene un lugar especial en mi corazón. Además, debido a algunas circunstancias fortuitas, estaba en el lugar correcto en el momento adecuado y logré salvar un PDP-8 que iba a ser desechado como basura. A continuación se muestra una fotografía de mi premio.

En este fin de semana especial, no hace mucho, decidí devolverle la vida al PDP-8, aunque solo sea para revivir esos preciosos recuerdos tempranos y mostrarle a mi hija lo bien que lo hace con su "miserable Pentium de 133 MHz". "

Revivir un clásico simulando otro

Para comenzar mi esfuerzo de avivamiento, tuve que introducir un programa en el PDP-8. En el PDP-8, esto se logra siguiendo un proceso de tres pasos:

  1. Usando los interruptores del panel frontal, el usuario "introduce" un programa corto en la memoria del núcleo magnético. Este programa se llama RIM Loader y su propósito es cargar otro programa desde una cinta de papel que esté en formato Read-in-Mode o RIM.

  2. RIM Loader carga la cinta de papel en formato RIM. Esta cinta contiene un programa llamado BIN Loader, que puede cargar programas desde una cinta de papel en formato binario (BIN).

  3. Finalmente, ejecuta BIN Loader para cargar el programa que realmente desea, que está en una cinta de papel en formato BIN. ¡Uf!

Después de seguir estos tres pasos, el programa que desea ejecutar se almacena en la memoria central. Todo lo que el usuario debe hacer es configurar la dirección de inicio y decirle a la máquina que "vaya".

En mi esfuerzo por reactivar la máquina, el Paso 1 no fue un problema, pero el Paso 2 implicó el uso del lector de cinta de papel en el Teletipo, y no tenía un Teletipo. Por supuesto, lo tengo a mi computadora de escritorio, por lo que el paso lógico era simular un lector de cinta de papel en mi escritorio.

Desde un punto de vista lógico y de programación, simular un lector de cinta de papel es trivial. Simplemente lee un archivo que contiene los datos de la "cinta", envíalo a un puerto serie a 110 baudios (sí, solo 10 caracteres por segundo), hasta que hayas agotado el archivo. Podría escribir un programa en C en mi sistema Solaris o en mi sistema FreeBSD en unos 10 minutos que podría hacer esto, pero recuerde, estaba en un sistema Windows 95, no en un sistema Unix.

De malo a feo y viceversa

Sabía que podía escribir fácilmente este programa en C, así que ese era mi idioma preferido. Mala elección. Abrí mi copia de Visual C ++ 5.0 y saqué un programa simple llamado sendtape.c que llamaba open()al puerto de comunicaciones. Intenté configurarlo en modo RAW (el modo en Unix en el que el sistema operativo no intenta interpretar nada en el puerto serie como entrada del usuario) y luego intenté compilarlo. Vaya, sin ioctl()función ni ttyfunciones: ¡nada, zip, zilch!

No hay problema, pensé para mis adentros: "Tengo toda la biblioteca de la red de desarrolladores de software de Microsoft en CD con mi compilador de C; haré una búsqueda rápida en las palabras clave 'puerto COM'".

La búsqueda arrojó muchas referencias al Modelo de objetos componentes de Microsoft (también llamado COM), y también referencias a MSComm. MSComm es una clase de C ++ que proporciona Microsoft para comunicarse con los puertos serie. Miré los ejemplos y me horrorizó la cantidad de código que se necesitaría para hacer algo tan simple como escribir bytes en el puerto serie a 110 baudios. Todo lo que quería hacer era abrir el maldito puerto serie, establecer su velocidad en baudios y rellenarlo unos pocos bytes, ¡no crear una nueva clase de aplicaciones mejoradas de comunicaciones serie!

Sentado frente a mi monitor estaba el receptor Blue Dot para mi Java Ring, y pensé: "¡Ajá! La gente de Dallas Semiconductor ha descubierto cómo comunicarse con un puerto serie en la PC. Veamos qué hacen. " Después de revisar el código fuente de la empresa para Win32, quedó claro que hablar con los puertos serie no sería una tarea sencilla.

Java al rescate

En este punto de mi fin de semana, estaba pensando que quizás arrastraría una de mis máquinas Unix al laboratorio para codificar el programa en él en lugar de usar lo que ya tenía. Luego recordé mi experiencia con Java Ring y el paquete java.comm de Sun. En su lugar, decidí seguir esa avenida.

¿Qué proporciona java.comm?

La API de comunicaciones de Java, o java.comm, proporciona un método independiente de la plataforma para acceder a los puertos serie y paralelo desde Java. Al igual que con otras API de Java como JFC, JDBC y Java 3D, el programador obliga a un cierto nivel de direccionamiento indirecto a aislar la idea de la plataforma de "qué es un puerto serie" del modelo de programación. En el caso del diseño de javax.comm, los elementos como los nombres de los dispositivos, que varían de una plataforma a otra, nunca se utilizan directamente. Las tres interfaces de la API proporcionan acceso independiente de la plataforma a puertos serie y paralelo. Estas interfaces proporcionan llamadas a métodos para enumerar los puertos de comunicación disponibles, controlar el acceso compartido y exclusivo a los puertos y controlar las características específicas del puerto, como la velocidad en baudios, la generación de paridad y el control de flujo.

Cuando vi el ejemplo SimpleWrite.java en la documentación, y comparé sus 40 líneas de código con las 150 a 200 líneas de código que estaba buscando escribir en C, supe que la solución estaba a mano.

La abstracción de alto nivel para este paquete es la clase javax.comm.CommPort. La CommPortclase define el tipo de cosas que normalmente haría con un puerto, lo que incluye obtener InputStreamy OutputStreamobjetos que son los canales de E / S del puerto. losCommPortLa clase también incluye métodos para controlar el tamaño del búfer y ajustar cómo se maneja la entrada. Como sabía que estas clases admitían el protocolo Dallas Semiconductor One-Wire (un protocolo que implicaba cambios dinámicos en la velocidad en baudios y una transparencia total de los bytes que se transfieren), sabía que la API javax.comm tenía que ser flexible. Lo que fue una sorpresa agradable fue lo ajustadas que eran las clases: tenían la flexibilidad suficiente para hacer el trabajo y nada más. Había poco o ningún bloatware innecesario en forma de "métodos de conveniencia" o soporte de protocolos de módem como Kermit o xmodem.

Una clase compañera CommPortes la javax.comm.CommPortIdentifierclase. Esta clase abstrae la relación entre cómo se nombra un puerto en un sistema en particular (es decir, "/ dev / ttya" en sistemas Unix y "COM1" en sistemas Windows) y cómo se descubren los puertos. El método estático getCommPortIdentifiersenumerará todos los puertos de comunicación conocidos en el sistema; además, puede agregar sus propios nombres de puerto para pseudo puertos de comunicación usando el addPortNamemétodo.

La CommPortclase es realmente abstracta, y lo que obtienes de una invocación de openPorten CommPortIdentifieres una subclase de CommPorteso es ParallelPorto SerialPort. Cada una de estas dos subclases tiene métodos adicionales que le permiten controlar el puerto en sí.

El poder de Java

You can argue about the reality of "write once, run anywhere" all you want, but I will tell you from experience that for single- threaded or even simple multithreaded non-GUI applications, Java is there. Specifically, if you want to write a program that runs on Unix systems, Win32, and Mac systems, and can access the serial port, then Java is the only solution today.

The benefit here is that fewer resources are required to maintain code that runs on a large number of platforms -- and this reduces cost.

A number of applications share a requirement to have pretty low-level access to the serial port. The term low-level in this context means that a program has access to interfaces that allow it to change modes on-the-fly and directly sample and change the states of the hardware flow-control pins. Besides my PDP-8 project, Dallas Semiconductor needed to use its Blue Dot interfaces on serial ports to talk to the iButton with Java. In addition, the makers of microprocessors have evaluation boards that use a serial port for communications and program loading. All of these applications can now be completely, and portably, written in Java -- a pretty powerful statement.

All of this power to control the parallel and serial ports of the host machine comes from the javax.comm library. Giving Java programmers access to the ports opens up an entirely new set of applications that target embedded systems. In my case, it gave me the ability to write my TTY paper-tape reader emulator completely in Java.

How do you get to play with this stuff?

To get a copy of the latest javax.comm distribution, first you need to sign up as a developer on the Java Developer Connection (JDC) if you haven't done so already. (See Resources.) JDC is free, and as a member you will get early access to Java classes that will eventually be part of the final product.

Go to the Java Communications API section and download the latest javax.comm archive file. Unpack the file and install the shared libraries (yes, the Java virtual machine needs native code to talk to the ports -- fortunately for you, you don't have to write it), and install the comm.jar file. Finally, add the comm.jar file to your CLASSPATH variable.

Once the comm.jar file is stored in the lib directory of your Java installation, and the win32comm.dll is stored in the bin directory of your Java installation, you can compile and run all the examples that come with the download. I encourage you to look them over as there is lots of good information nestled in with the source code.

Where does this leave the PDP-8?

So, what's happened with the PDP-8? I thought you'd never ask! After reading the README document that came with the javax.comm distribution, then scanning the JavaDocs for the javax.comm package, I put together an application class called SendTape. This class simulates a paper-tape reader by opening the serial port and stuffing bytes over it at 110 baud. The code for this class is shown here:

import javax.comm.*; import java.io.*; public class SendTape { static final int LEADER = 0; static final int COLLECT_ADDR = 1; static final int COLLECT_DATA = 2; static final int COLLECT_DATA2 = 3; /* This array holds a copy of the BIN format loader */ static byte binloader[] = { (byte) 0x80,(byte) 0x80,(byte) 0x80,(byte) 0x80, ... (byte) 0x80,(byte) 0x80, }; 

The code fragment above is the first part of the SendTape class. This class begins by implicitly importing all classes in the javax.comm package and the java.io packages. The SendTape class then defines some constants and pre-initializes a byte array to contain the BIN Loader program I mentioned earlier. I included the BIN Loader because it is always needed when initializing the memory of the PDP-8 and I kept losing track of where I had last stored the file containing its image in RIM format. With this crucial paper tape image embedded in the class in this way, I always have the ability to load it with this class.

 /** * This method runs a mini-state machine that gives * a useful human readable output of what is happening * with the download. */ static int newState(int oldState, byte b) { ... } 

Después de la inicialización, tiene el código para el método newState, que se muestra arriba, que rastrea el contenido de la cinta de papel (ya sea información de dirección o información de programación). El método anterior también imprime un mensaje para cada ubicación de la memoria en el PDP-8 que se inicializa.

A continuación, tiene el mainmétodo, que se muestra a continuación; abre el archivo y lo lee. Luego, el código abre el puerto serie y establece sus parámetros de comunicación.