Ouverture de nouveaux ports vers Java avec javax.comm

J'ai découvert le package de classes javax.comm lorsque j'ai découvert qu'elles étaient utilisées dans le kit de développement de Java Ring. (Pour plus de détails sur javax.comm, voir la colonne Java Developer de Rinaldo Di Giorgio dans le numéro de mai de JavaWorld: "Java reçoit un support en série avec le nouveau paquet javax.comm.") Pendant ma course folle à JavaOne pour mettre un programme dans mon ring, j'ai rencontré une variété de problèmes, dont le moindre n'était pas de communiquer avec le ring. J'ai téléchargé la distribution à partir de Java Developer Connection et j'ai essayé sans succès de l'utiliser pour parler à Java Ring. Plus tard, j'ai découvert le problème avec mon anneau: je n'avais pas installé correctement les API héritées de Dallas Semiconductor. L'anneau fonctionnant, j'ai pratiquement oublié le paquet de communications. Autrement dit, jusqu'à un week-end il y a environ un mois, qui est le point de départ de cette histoire.

Pour de nombreuses raisons différentes (principalement liées à des environnements simulés hautement interactifs - par exemple, des jeux), l'ordinateur principal de mon «laboratoire» exécute Windows 95. Cependant, ce week-end, j'étais plus préoccupé par un autre ordinateur qui, en à bien des égards, était à peu près aussi puissant que le Java Ring: une Digital Equipment Corporation PDP-8 / e.

Le PDP-8 était sans doute le premier véritable ordinateur personnel. Conçu à la fin des années 1960 et produit en quantités relativement élevées dans les années 70, le PDP-8 pouvait être soulevé par un seul individu, était alimenté par un courant de ligne de 120 volts et coûtait moins de 0,000. La plupart de ces ordinateurs sont livrés avec un seul périphérique: un terminal Teletype Model ASR-33 - le "TTY" original dans le jargon informatique.

Le télétype ASR-33 était un terminal d'impression livré avec un lecteur de bande papier et une perforatrice. Oui, c'était du ruban de papier, du papier de 1 "de large avec des trous perforés, qui était le support de stockage principal pour les programmes sur le PDP-8.

Le PDP-8 a été le premier ordinateur que j'ai jamais programmé et il a donc une place spéciale dans mon cœur. De plus, en raison de circonstances fortuites, j'étais au bon endroit au bon moment et j'ai réussi à sauver un PDP-8 qui allait être mis au rebut. Une photographie de mon prix est présentée ci-dessous.

En ce week-end spécial, il n'y a pas si longtemps, j'ai décidé de redonner vie au PDP-8, ne serait-ce que pour revivre ces précieux premiers souvenirs et montrer à ma fille à quel point elle l'a bien avec son "vieux Pentium de 133 MHz. "

Faire revivre un classique en simulant un autre

Pour commencer mon effort de réveil, je devais insérer un programme dans le PDP-8. Sur le PDP-8, ceci est réalisé en suivant un processus en trois étapes:

  1. En utilisant les commutateurs du panneau avant, l'utilisateur "touche" un programme court dans la mémoire à noyau magnétique. Ce programme s'appelle RIM Loader et son objectif est de charger un autre programme à partir d'une bande de papier au format Read-in-Mode, ou RIM.

  2. RIM Loader charge la bande de papier au format RIM. Cette bande contient un programme appelé BIN Loader, qui peut charger des programmes à partir d'une bande papier au format binaire (BIN).

  3. Enfin, vous exécutez BIN Loader pour charger le programme que vous voulez vraiment, qui se trouve sur une bande de papier au format BIN. Ouf!

Après avoir suivi ces trois étapes, le programme que vous souhaitez exécuter est stocké dans la mémoire centrale. Tout ce que l'utilisateur doit faire est alors de définir l'adresse de départ et de dire à la machine de "partir".

Dans mes efforts pour relancer la machine, l'étape 1 n'a pas posé de problème, mais l'étape 2 impliquait l'utilisation du lecteur de bande papier dans le télétype - et je n'avais pas de télétype. Bien sûr, je n'ai mon ordinateur de bureau, donc l'étape logique était de simuler un lecteur de bande de papier sur mon bureau.

D'un point de vue logique et de programmation, simuler un lecteur de bande papier est trivial. Vous lisez simplement un fichier qui contient les données de la «bande», envoyez-le vers un port série à 110 bauds (oui, seulement 10 caractères par seconde), jusqu'à ce que vous ayez épuisé le fichier. Je pourrais écrire un programme en C sur mon système Solaris ou mon système FreeBSD en environ 10 minutes qui pourrait le faire - mais, rappelez-vous, j'étais sur un système Windows 95, pas un système Unix.

De mauvais à laid et inversement

Je savais que je pourrais facilement écrire ce programme en C, c'était donc ma langue de choix. Mauvais choix. J'ai apporté ma copie de Visual C ++ 5.0 et sorti un programme simple appelé sendtape.c qui appelait open()le port de communication. J'ai essayé de le mettre en mode RAW (le mode sous Unix où le système d'exploitation n'essaye pas d'interpréter quoi que ce soit sur le port série comme entrée utilisateur), puis j'ai essayé de le compiler. Oups, pas de ioctl()fonction ou de ttyfonctions - nada, zip, zilch!

Pas de problème, je me suis dit: "J'ai toute la bibliothèque de Microsoft Software Developer's Network sur CD avec mon compilateur C; je vais faire une recherche rapide sur les mots-clés" port COM "."

La recherche a révélé de nombreuses références au modèle d'objet de composant Microsoft (également appelé COM), ainsi que des références à MSComm. MSComm est une classe C ++ que Microsoft fournit pour communiquer avec les ports série. J'ai regardé les exemples et j'ai été consterné de voir combien de code il faudrait pour faire une chose aussi simple que d'écrire des octets sur le port série à 110 bauds. Tout ce que je voulais faire était d'ouvrir le sacré port série, de définir sa vitesse de transmission et de le réduire de quelques octets - pas de créer une nouvelle classe d'applications améliorées par les communications série!

Assis devant mon moniteur se trouvait le récepteur Blue Dot de mon Java Ring, et je me suis dit: "Aha! Les gens de Dallas Semiconductor ont trouvé comment parler à un port série sur le PC. Voyons ce qu'ils font. " Après avoir parcouru le code source de la société pour Win32, il était clair que parler aux ports série n'allait pas être une tâche simple.

Java à la rescousse

À ce moment de mon week-end, je pensais peut-être que je ferais glisser une de mes machines Unix vers le laboratoire afin de coder le programme dessus au lieu d'utiliser ce que j'avais déjà. Puis je me suis souvenu de mon expérience avec le Java Ring et le package java.comm de Sun. J'ai décidé de poursuivre dans cette voie à la place.

Que fournit java.comm?

L'API Java Communications - ou java.comm - fournit une méthode indépendante de la plate-forme pour accéder aux ports série et parallèle à partir de Java. Comme avec d'autres API Java telles que JFC, JDBC et Java 3D, un certain niveau d'indirection est forcé sur le programmeur pour isoler l'idée de la plate-forme de «ce qu'est un port série» du modèle de programmation. Dans le cas de la conception javax.comm, des éléments tels que les noms de périphériques, qui varient d'une plate-forme à l'autre, ne sont jamais utilisés directement. Les trois interfaces de l'API fournissent un accès indépendant de la plate-forme aux ports série et parallèle. Ces interfaces fournissent des appels de méthode pour répertorier les ports de communication disponibles, contrôler l'accès partagé et exclusif aux ports et contrôler des fonctionnalités de port spécifiques telles que la vitesse de transmission, la génération de parité et le contrôle de flux.

Quand j'ai vu l'exemple SimpleWrite.java dans la documentation et comparé ses 40 lignes de code aux 150 à 200 lignes de code que je cherchais à écrire en C, je savais que la solution était à portée de main.

L'abstraction de haut niveau pour ce package est la classe javax.comm.CommPort. La CommPortclasse définit les types de choses que vous feriez généralement avec un port, ce qui inclut l'obtention InputStreamet les OutputStreamobjets qui sont les canaux d'E / S pour le port. leCommPortLa classe inclut également des méthodes pour contrôler la taille des tampons et ajuster la façon dont les entrées sont gérées. Puisque je savais que ces classes supportaient le protocole Dallas Semiconductor One-Wire (un protocole qui impliquait des changements dynamiques de la vitesse de transmission et une transparence totale des octets transférés), je savais que l'API javax.comm devait être flexible. Ce qui a été une agréable surprise, c'est à quel point les classes étaient serrées: ils avaient juste assez de flexibilité pour faire le travail et rien de plus. Il y avait peu ou pas de bloatware inutile sous la forme de «méthodes pratiques» ou de support de protocoles de modem comme Kermit ou 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) { ... } 

Après l'initialisation, vous disposez du code de la méthode newState, illustré ci-dessus, qui suit le contenu de la bande de papier (qu'il s'agisse d'informations d'adresse ou d'informations de programmation). La méthode ci-dessus imprime également un message pour chaque emplacement de mémoire sur le PDP-8 qui est initialisé.

Ensuite, vous avez la mainméthode, qui est illustrée ci-dessous; il ouvre le fichier et le lit. Ensuite, le code ouvre le port série et définit ses paramètres de communication.