Apertura di nuove porte a Java con javax.comm

Sono stato presentato al pacchetto di classi javax.comm quando ho scoperto che erano utilizzate nel kit di sviluppo per Java Ring. (Per i dettagli su javax.comm, vedere la colonna Java Developer di Rinaldo Di Giorgio nel numero di maggio di JavaWorld: "Java ottiene il supporto seriale con il nuovo pacchetto javax.comm.") Durante la mia folle corsa in JavaOne per avere un programma nel mio ring, ho riscontrato una serie di problemi, non ultimo dei quali era la comunicazione con l'anello. Ho scaricato la distribuzione da Java Developer Connection e ho provato senza successo a usarla per parlare con Java Ring. Successivamente, ho scoperto il problema con il mio anello: non avevo installato correttamente le API legacy di Dallas Semiconductor. Con l'anello funzionante, ho praticamente dimenticato il pacchetto di comunicazioni. Cioè, fino a un fine settimana di circa un mese fa, che è il punto di partenza di questa storia.

Per molti motivi diversi (principalmente legati ad ambienti simulati altamente interattivi, ad esempio i giochi), il computer principale nel mio "laboratorio" esegue Windows 95. Tuttavia, in questo particolare fine settimana ero più interessato a un altro computer che, in per molti versi, era potente quanto il Java Ring: una Digital Equipment Corporation PDP-8 / e.

Il PDP-8 è stato probabilmente il primo vero personal computer. Progettato alla fine degli anni '60 e prodotto in quantità relativamente elevate negli anni '70, il PDP-8 poteva essere sollevato da un singolo individuo, era alimentato da una corrente di linea da 120 volt e costava meno di 0.000. La maggior parte di questi computer viene fornita con una singola periferica: un terminale Teletype modello ASR-33 - il "TTY" originale nel gergo informatico.

La telescrivente ASR-33 era un terminale di stampa fornito con un lettore di nastro di carta e un punzone. Sì, era nastro di carta, carta larga 1 "con fori perforati, che era il supporto di memorizzazione principale per i programmi sul PDP-8.

Il PDP-8 è stato il primo computer che io abbia mai programmato e quindi occupa un posto speciale nel mio cuore. Inoltre, a causa di alcune circostanze fortuite, ero nel posto giusto al momento giusto e sono riuscito a salvare un PDP-8 che stava per essere scartato come spazzatura. Di seguito è mostrata una fotografia del mio premio.

In questo fine settimana speciale, non molto tempo fa, ho deciso di riportare in vita il PDP-8, se non altro per rivivere quei primi preziosi ricordi e per mostrare a mia figlia quanto è brava con il suo "misero Pentium a 133 MHz". "

Far rivivere un classico simulandone un altro

Per iniziare il mio sforzo di rinascita, ho dovuto inserire un programma nel PDP-8. Sul PDP-8, ciò si ottiene seguendo un processo in tre fasi:

  1. Utilizzando gli interruttori del pannello anteriore, l'utente "inserisce" un breve programma nella memoria del nucleo magnetico. Questo programma è chiamato RIM Loader e il suo scopo è caricare un altro programma dal nastro di carta in formato Read-in-Mode o RIM.

  2. RIM Loader carica il nastro di carta in formato RIM. Questo nastro contiene un programma chiamato BIN Loader, che può caricare programmi dal nastro di carta in formato binario (BIN).

  3. Infine, esegui BIN Loader per caricare il programma che desideri veramente, che è su un nastro di carta in formato BIN. Whew!

Dopo aver eseguito questi tre passaggi, il programma che si desidera eseguire viene archiviato nella memoria principale. Tutto ciò che l'utente deve fare è quindi impostare l'indirizzo di partenza e dire alla macchina di "andare".

Nel mio tentativo di rianimare la macchina, il passaggio 1 non è stato un problema, ma il passaggio 2 prevedeva l'uso del lettore di nastro di carta nel Teletype - e non avevo un Teletype. Certo, ho fatto il mio computer desktop, in modo che il passo logico è stato quello di simulare un lettore di nastro di carta sul mio desktop.

Da un punto di vista logico e di programmazione, simulare un lettore di nastro di carta è banale. Basta leggere un file che contiene i dati del "nastro", inviarlo a una porta seriale a 110 baud (sì, solo 10 caratteri al secondo), finché non si è esaurito il file. Potrei scrivere un programma in C sul mio sistema Solaris o sul mio sistema FreeBSD in circa 10 minuti che potrebbe farlo - ma, ricorda, ero su un sistema Windows 95, non un sistema Unix.

Dal cattivo al brutto e viceversa

Sapevo di poter scrivere facilmente questo programma in C, quindi quella era la mia lingua preferita. Scelta sbagliata. Ho aperto la mia copia di Visual C ++ 5.0 e ho tirato fuori un semplice programma chiamato sendtape.c che chiamava open()la porta di comunicazione. Ho provato a impostarlo in modalità RAW (la modalità in Unix dove il sistema operativo non tenta di interpretare nulla sulla porta seriale come input dell'utente) e poi ho provato a compilarlo. Ops, nessuna ioctl()funzione o ttyfunzioni - nada, zip, zilch!

Nessun problema, ho pensato: "Ho tutta la libreria di rete di Microsoft Software Developer su CD con il mio compilatore C; farò una rapida ricerca con le parole chiave 'porta COM'".

La ricerca ha prodotto molti riferimenti al Microsoft Component Object Model (chiamato anche COM) e anche riferimenti a MSComm. MSComm è una classe C ++ fornita da Microsoft per comunicare con le porte seriali. Ho guardato gli esempi e sono rimasto sbalordito dalla quantità di codice necessaria per fare una cosa così semplice come scrivere byte sulla porta seriale a 110 baud. Tutto quello che volevo fare era aprire la dannata porta seriale, impostare la sua velocità di trasmissione e riempirla di pochi byte, non creare una nuova classe di applicazioni potenziate per le comunicazioni seriali!

Seduto davanti al mio monitor c'era il ricevitore Blue Dot per il mio Java Ring, e ho pensato tra me e me: "Aha! I ragazzi di Dallas Semiconductor hanno capito come parlare con una porta seriale del PC. Vediamo cosa fanno. " Dopo aver esaminato il codice sorgente dell'azienda per Win32, era chiaro che parlare con le porte seriali non sarebbe stato un compito semplice.

Java in soccorso

A questo punto del mio weekend, stavo pensando che forse avrei trascinato una delle mie macchine Unix in laboratorio per codificare il programma su di essa invece di usare quello che avevo già. Poi ho ricordato la mia esperienza con Java Ring e il pacchetto java.comm di Sun. Ho deciso invece di seguire quella strada.

Cosa fornisce java.comm?

Java Communications API, o java.comm, fornisce un metodo indipendente dalla piattaforma per accedere alle porte seriali e parallele da Java. Come con altre API Java come JFC, JDBC e Java 3D, il programmatore impone un certo livello di riferimento indiretto per isolare l'idea della piattaforma di "cos'è una porta seriale" dal modello di programmazione. Nel caso del design javax.comm, elementi come i nomi dei dispositivi, che variano da piattaforma a piattaforma, non vengono mai utilizzati direttamente. Le tre interfacce dell'API forniscono un accesso indipendente dalla piattaforma alle porte seriali e parallele. Queste interfacce forniscono chiamate di metodo per elencare le porte di comunicazione disponibili, controllare l'accesso condiviso ed esclusivo alle porte e controllare le caratteristiche specifiche della porta come la velocità di trasmissione, la generazione della parità e il controllo del flusso.

Quando ho visto l'esempio SimpleWrite.java nella documentazione e ho confrontato le sue 40 righe di codice con le 150-200 righe di codice che stavo cercando di scrivere in C, sapevo che la soluzione era a portata di mano.

L'astrazione di alto livello per questo pacchetto è la classe javax.comm.CommPort. La CommPortclasse definisce il tipo di cose che faresti tipicamente con una porta, che include il recupero InputStreame gli OutputStreamoggetti che sono i canali di I / O per la porta. IlCommPortinclude anche metodi per controllare le dimensioni del buffer e regolare il modo in cui l'input viene gestito. Poiché sapevo che queste classi supportavano il protocollo Dallas Semiconductor One-Wire (un protocollo che comportava modifiche dinamiche nella velocità di trasmissione e completa trasparenza sui byte trasferiti), sapevo che l'API javax.comm doveva essere flessibile. Quella che è stata una piacevole sorpresa è stata quanto fossero strette le lezioni: avevano la flessibilità sufficiente per portare a termine il lavoro e non di più. C'era poco o nessun bloatware inutile sotto forma di "metodi di convenienza" o supporto di protocolli modem come Kermit o xmodem.

Una classe companion a CommPortè la javax.comm.CommPortIdentifierclasse. Questa classe astrae la relazione tra il modo in cui una porta è denominata su un particolare sistema (cioè, "/ dev / ttya" su sistemi Unix e "COM1" su sistemi Windows) e come vengono scoperte le porte. Il metodo statico getCommPortIdentifierselencherà tutte le porte di comunicazione conosciute sul sistema; inoltre, è possibile aggiungere i propri nomi di porta per le pseudo porte di comunicazione utilizzando il addPortNamemetodo.

La CommPortclasse è in realtà astratta, e quello che si ottiene indietro da un'invocazione openPortin CommPortIdentifierè una sottoclasse di CommPortche è o ParallelPorto SerialPort. Ciascuna di queste due sottoclassi dispone di metodi aggiuntivi che consentono di controllare la porta stessa.

La potenza di 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) { ... } 

Dopo l'inizializzazione, si dispone del codice per il metodo newState, mostrato sopra, che tiene traccia del contenuto del nastro di carta (sia che si tratti di informazioni sull'indirizzo o informazioni di programmazione). Il metodo precedente stampa anche un messaggio per ogni posizione di memoria sul PDP-8 inizializzata.

Successivamente hai il mainmetodo, che è mostrato di seguito; apre il file e lo legge. Quindi il codice apre la porta seriale e ne imposta i parametri di comunicazione.