Öffnen neuer Ports für Java mit javax.comm

Ich wurde in das Klassenpaket javax.comm eingeführt, als ich entdeckte, dass sie im Entwicklungskit für den Java Ring verwendet wurden. (Einzelheiten zu javax.comm finden Sie in der Java Developer- Spalte von Rinaldo Di Giorgio in der Mai-Ausgabe von JavaWorld: "Java erhält serielle Unterstützung mit dem neuen Paket javax.comm.") Während meines wahnsinnigen Ansturms bei JavaOne, ein Programm in meinen Ring zu bekommen, stieß ich auf eine Reihe von Problemen, von denen nicht zuletzt die Kommunikation mit dem Ring bestand. Ich habe die Distribution von der Java Developer Connection heruntergeladen und erfolglos versucht, sie für die Kommunikation mit dem Java Ring zu verwenden. Später entdeckte ich das Problem mit meinem Ring: Ich hatte die Legacy-APIs von Dallas Semiconductor nicht richtig installiert. Während der Ring funktionierte, vergaß ich im Grunde das Kommunikationspaket. Das heißt, bis zu einem Wochenende vor ungefähr einem Monat, das ist der Ausgangspunkt für diese Geschichte.

Aus vielen verschiedenen Gründen (hauptsächlich im Zusammenhang mit hochgradig interaktiven simulierten Umgebungen - zum Beispiel Spielen) wird auf dem Primärcomputer in meinem "Labor" Windows 95 ausgeführt. An diesem speziellen Wochenende beschäftigte ich mich jedoch mehr mit einem anderen Computer, der in In vielerlei Hinsicht war es ungefähr so ​​leistungsfähig wie der Java Ring: ein PDP-8 / e der Digital Equipment Corporation.

Der PDP-8 war wohl der erste echte Personal Computer. Der PDP-8 wurde Ende der 1960er Jahre entwickelt und in den 70er Jahren in relativ hohen Stückzahlen hergestellt. Er konnte von einer einzelnen Person angehoben werden, wurde mit einem 120-Volt-Netzstrom betrieben und kostete weniger als 0,000. Die meisten dieser Computer werden mit einem einzigen Peripheriegerät ausgeliefert: einem Teletyp-Terminal vom Typ ASR-33 - dem ursprünglichen "TTY" im Computerjargon.

Der Teletyp ASR-33 war ein Druckterminal, das mit einem Papierbandleser und einem Locher geliefert wurde. Ja, es war Papierband, 1 "breites Papier mit Löchern, das das primäre Speichermedium für Programme auf dem PDP-8 war.

Der PDP-8 war der erste Computer, den ich jemals programmiert habe, und hat daher einen besonderen Platz in meinem Herzen. Außerdem war ich aufgrund einiger zufälliger Umstände zur richtigen Zeit am richtigen Ort und konnte einen PDP-8 retten, der als Müll verschrottet werden sollte. Ein Foto meines Preises ist unten gezeigt.

An diesem besonderen Wochenende vor nicht allzu langer Zeit habe ich beschlossen, den PDP-8 wieder zum Leben zu erwecken, um diese wertvollen frühen Erinnerungen noch einmal zu erleben und meiner Tochter zu zeigen, wie gut sie es mit ihrem "mickrigen alten 133-MHz-Pentium" hat. ""

Wiederbelebung eines Klassikers durch Simulation eines anderen

Um meine Wiederbelebungsbemühungen zu beginnen, musste ich ein Programm in den PDP-8 einbinden. Auf dem PDP-8 wird dies durch einen dreistufigen Prozess erreicht:

  1. Mit den Schaltern auf der Vorderseite "tippt" der Benutzer ein kurzes Programm in den Magnetkernspeicher. Dieses Programm wird als RIM Loader bezeichnet und dient zum Laden eines anderen Programms von Papierband im Readim-in-Mode- oder RIM-Format.

  2. RIM Loader lädt das Papierband im RIM-Format. Dieses Band enthält ein Programm namens BIN Loader, mit dem Programme vom Papierband im Binärformat (BIN) geladen werden können.

  3. Schließlich führen Sie BIN Loader aus, um das gewünschte Programm auf ein Papierband im BIN-Format zu laden. Wütend!

Nachdem Sie diese drei Schritte ausgeführt haben, wird das Programm, das Sie ausführen möchten, im Kernspeicher gespeichert. Alles, was der Benutzer dann tun muss, ist die Startadresse einzustellen und die Maschine anzuweisen, "los" zu gehen.

Bei meinen Bemühungen, die Maschine wiederzubeleben, war Schritt 1 kein Problem, aber Schritt 2 beinhaltete die Verwendung des Papierbandlesegeräts im Teletyp - und ich hatte keinen Teletyp. Natürlich, ich habe meine Desktop - Computer habe, so der logische Schritt einen Lochstreifenleser auf meinem Desktop zu simulieren war.

Aus logischer und programmtechnischer Sicht ist die Simulation eines Papierbandlesegeräts trivial. Sie lesen einfach eine Datei, die die Daten vom "Band" enthält, und senden sie mit 110 Baud (ja, nur 10 Zeichen pro Sekunde) an eine serielle Schnittstelle, bis Sie die Datei erschöpft haben. Ich könnte in ungefähr 10 Minuten ein Programm in C auf meinem Solaris-System oder meinem FreeBSD-System schreiben, das dies könnte - aber denken Sie daran, ich war auf einem Windows 95-System, nicht auf einem Unix-System.

Von schlecht zu hässlich und wieder zurück

Ich wusste, dass ich dieses Programm leicht in C schreiben konnte, also war das meine bevorzugte Sprache. Schlechte Wahl. Ich habe meine Kopie von Visual C ++ 5.0 aufgerufen und ein einfaches Programm namens sendtape.c herausgebracht, das open()den Kommunikationsport aufgerufen hat . Ich habe versucht, es in den RAW- Modus zu versetzen (den Modus unter Unix, in dem das Betriebssystem nicht versucht, etwas an der seriellen Schnittstelle als Benutzereingabe zu interpretieren) und dann versucht, es zu kompilieren. Hoppla, keine ioctl()Funktion oder ttyFunktionen - nada, zip, zilch!

Kein Problem, dachte ich mir: "Ich habe die gesamte Netzwerkbibliothek des Microsoft Software Developer mit meinem C-Compiler auf CD. Ich werde eine schnelle Suche nach den Schlüsselwörtern 'COM-Port' durchführen."

Bei der Suche wurden viele Verweise auf das Microsoft Component Object Model (auch als COM bezeichnet) sowie Verweise auf MSComm gefunden. MSComm ist eine C ++ - Klasse, die Microsoft bereitstellt, um mit den seriellen Schnittstellen zu kommunizieren. Ich sah mir die Beispiele an und war entsetzt darüber, wie viel Code erforderlich wäre, um so einfach wie das Schreiben von Bytes an die serielle Schnittstelle mit 110 Baud zu tun. Alles, was ich tun wollte, war, die verdammte serielle Schnittstelle zu öffnen, die Baudrate einzustellen und ein paar Bytes nach unten zu stopfen - keine neue Klasse von Anwendungen mit verbesserter serieller Kommunikation zu erstellen!

Vor meinem Monitor saß der Blue Dot-Rezeptor für meinen Java-Ring, und ich dachte mir: "Aha! Die Leute von Dallas Semiconductor haben herausgefunden, wie man mit einer seriellen Schnittstelle am PC spricht. Mal sehen, was sie tun. "" Nach Durchsicht des Quellcodes des Unternehmens für Win32 war klar, dass die Kommunikation mit seriellen Schnittstellen keine einfache Aufgabe sein würde.

Java zur Rettung

Zu diesem Zeitpunkt an meinem Wochenende dachte ich, ich würde vielleicht eine meiner Unix-Maschinen ins Labor ziehen, um das Programm darauf zu codieren , anstatt das zu verwenden, was ich bereits hatte. Dann erinnerte ich mich an meine Erfahrungen mit dem Java Ring und dem java.comm-Paket von Sun. Ich beschloss, stattdessen diesen Weg zu gehen.

Was bietet java.comm?

Die Java Communications API - oder java.comm - bietet eine plattformunabhängige Methode für den Zugriff auf serielle und parallele Ports von Java aus. Wie bei anderen Java-APIs wie JFC, JDBC und Java 3D wird dem Programmierer eine bestimmte Indirektionsebene aufgezwungen, um die Idee der Plattform, "was eine serielle Schnittstelle ist", vom Programmiermodell zu isolieren. Im Fall des javax.comm-Designs werden Elemente wie Gerätenamen, die von Plattform zu Plattform variieren, niemals direkt verwendet. Die drei Schnittstellen der API bieten plattformunabhängigen Zugriff auf serielle und parallele Ports. Diese Schnittstellen bieten Methodenaufrufe, um die verfügbaren Kommunikationsports aufzulisten, den gemeinsamen und exklusiven Zugriff auf Ports zu steuern und bestimmte Portfunktionen wie Baudrate, Paritätsgenerierung und Flusskontrolle zu steuern.

Als ich das Beispiel SimpleWrite.java in der Dokumentation sah und seine 40 Codezeilen mit den 150 bis 200 Codezeilen verglich, die ich in C schreiben wollte, wusste ich, dass die Lösung zur Hand war.

Die Abstraktion auf hoher Ebene für dieses Paket ist die Klasse javax.comm.CommPort. Die CommPortKlasse definiert die Arten von Dingen, die Sie normalerweise mit einem Port ausführen würden, einschließlich Abrufen InputStreamund OutputStreamObjekte, die die E / A-Kanäle für den Port sind. DasCommPortDie Klasse enthält auch Methoden zum Steuern der Puffergrößen und zum Anpassen der Verarbeitung von Eingaben. Da ich wusste, dass diese Klassen das One-Wire-Protokoll von Dallas Semiconductor unterstützen (ein Protokoll, das dynamische Änderungen der Baudrate und vollständige Transparenz der übertragenen Bytes beinhaltete), wusste ich, dass die javax.comm-API flexibel sein musste. Als angenehme Überraschung kam, wie eng die Klassen waren: Sie hatten gerade genug Flexibilität, um die Arbeit zu erledigen, und nicht mehr. Es gab wenig bis gar keine unnötige Bloatware in Form von "Convenience-Methoden" oder der Unterstützung von Modemprotokollen wie Kermit oder xmodem.

A companion class to CommPort is the javax.comm.CommPortIdentifier class. This class abstracts the relationship between how a port is named on a particular system (that is, "/dev/ttya" on Unix systems, and "COM1" on Windows systems) and how ports are discovered. The static method getCommPortIdentifiers will list all known communication ports on the system; furthermore, you can add your own port names for pseudo communication ports using the addPortName method.

The CommPort class is actually abstract, and what you get back from an invocation of openPort in the CommPortIdentifier is a subclass of CommPort that is either ParallelPort or SerialPort. These two subclasses each have additional methods that let you control the port itself.

The power of 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) { ... } 

Nach der Initialisierung haben Sie den Code für die newStateoben gezeigte Methode , der den Inhalt des Papierbandes verfolgt (ob es sich um Adressinformationen oder Programmierinformationen handelt). Das obige Verfahren druckt auch eine Nachricht für jeden Speicherort auf dem PDP-8 aus, der initialisiert wird.

Als nächstes haben Sie die mainMethode, die unten gezeigt wird; Es öffnet die Datei und liest sie ein. Dann öffnet der Code die serielle Schnittstelle und legt seine Kommunikationsparameter fest.