Membuka port baru ke Java dengan javax.comm

Saya diperkenalkan dengan pakej kelas javax.comm ketika saya mendapati mereka digunakan dalam kit pengembangan untuk Java Ring. (Untuk perincian di javax.comm, lihat kolom Pengembang Java Rinaldo Di Giorgio dalam edisi Mei JavaWorld: "Java mendapat sokongan bersiri dengan pakej javax.comm baru.") Semasa kegilaan saya di JavaOne untuk mendapatkan program ke dalam deringan saya, saya menghadapi pelbagai masalah, tidak sedikit yang berkomunikasi dengan cincin. Saya memuat turun edaran dari Java Developer Connection dan tidak berjaya menggunakannya untuk bercakap dengan Java Ring. Kemudian, saya menemui masalah dengan cincin saya: Saya tidak memasang API warisan Dallas Semiconductor dengan betul. Dengan cincin berfungsi, saya pada dasarnya melupakan pakej komunikasi. Iaitu, sehingga satu hujung minggu kira-kira sebulan yang lalu, yang merupakan titik permulaan cerita ini.

Atas pelbagai sebab (kebanyakannya berkaitan dengan persekitaran simulasi yang sangat interaktif - misalnya permainan), komputer utama di "makmal" saya menjalankan Windows 95. Walau bagaimanapun, pada hujung minggu ini saya lebih mementingkan komputer lain yang, di banyak cara, sama kuatnya dengan Java Ring: sebuah Digital Equipment Corporation PDP-8 / e.

PDP-8 boleh dikatakan komputer peribadi pertama yang benar. Direka pada akhir 1960-an dan dihasilkan dalam jumlah yang cukup tinggi pada tahun 70-an, PDP-8 dapat diangkat oleh satu individu, dikuasakan oleh arus talian 120 volt, dan harganya kurang dari 0,000. Sebilangan besar komputer ini dihantar dengan satu periferal: terminal Model Teletype ASR-33 - "TTY" asal dalam bahasa komputer.

Teletype ASR-33 adalah terminal percetakan yang dilengkapi dengan pembaca pita kertas dan pukulan. Ya, itu adalah pita kertas, kertas selebar 1 "dengan lubang yang ditebuk di dalamnya, itu adalah media simpanan utama untuk program di PDP-8.

PDP-8 adalah komputer pertama yang pernah saya atur dan oleh itu ia mempunyai tempat yang istimewa di hati saya. Selanjutnya, kerana beberapa keadaan yang tidak disengajakan, saya berada di tempat yang tepat pada waktu yang tepat dan berjaya menyelamatkan PDP-8 yang akan dibuang sebagai sampah. Gambar hadiah saya ditunjukkan di bawah.

Pada hujung minggu yang istimewa ini tidak lama dahulu, saya memutuskan untuk menghidupkan kembali PDP-8, jika hanya untuk menghidupkan kembali kenangan awal yang berharga itu dan untuk menunjukkan kepada anak perempuan saya betapa baiknya ia memilikinya dengan Pentium 133-MHz yang tua. "

Membangkitkan semula satu klasik dengan mensimulasikan yang lain

Untuk memulakan usaha menghidupkan semula saya, saya harus memasukkan program ke PDP-8. Pada PDP-8, ini dapat dicapai dengan mengikuti proses tiga langkah:

  1. Dengan menggunakan suis panel depan, pengguna "mengunci" program pendek ke memori teras magnetik. Program ini disebut RIM Loader, dan tujuannya adalah memuatkan program lain dari pita kertas yang dalam format Read-in-Mode, atau RIM.

  2. RIM Loader memuatkan pita kertas dalam format RIM. Pita ini mengandungi program yang disebut BIN Loader, yang dapat memuatkan program dari pita kertas dalam format biner (BIN).

  3. Akhirnya, anda menjalankan BIN Loader untuk memuatkan program yang anda mahukan, yang terdapat pada pita kertas dalam format BIN. Wah!

Setelah melalui tiga langkah ini, program yang ingin anda jalankan disimpan dalam memori teras. Semua pengguna perlu lakukan kemudian menetapkan alamat permulaan dan memberitahu mesin untuk "pergi".

Dalam usaha saya menghidupkan semula mesin, Langkah 1 tidak ada masalah, tetapi Langkah 2 melibatkan penggunaan pembaca pita kertas di Teletype - dan saya tidak mempunyai Teletype. Sudah tentu, saya tidak mempunyai komputer desktop saya, jadi langkah logik adalah untuk mensimulasikan pembaca pita kertas di desktop saya.

Dari sudut logik dan pengaturcaraan, mensimulasikan pembaca pita kertas adalah remeh. Anda hanya membaca fail yang mengandungi data dari "tape", hantar ke port bersiri pada 110 baud (ya, hanya 10 aksara sesaat), sehingga fail anda habis. Saya dapat menulis program dalam C pada sistem Solaris saya atau sistem FreeBSD saya dalam masa 10 minit yang dapat melakukan ini - tetapi, ingat, saya menggunakan sistem Windows 95, bukan sistem Unix.

Dari buruk hingga hodoh dan kembali lagi

Saya tahu saya boleh menulis program ini dengan mudah dalam bahasa C, jadi itulah pilihan bahasa saya. Pilihan teruk. Saya membawa salinan Visual C ++ 5.0 saya dan mengeluarkan satu program ringkas bernama sendtape.c yang memanggil open()port komunikasi. Saya cuba memasukkannya ke dalam mod RAW (mod di Unix di mana sistem operasi tidak cuba menafsirkan apa-apa pada port bersiri sebagai input pengguna) dan kemudian cuba menyusunnya. Ups, tiada ioctl()fungsi atau ttyfungsi - nada, zip, zilch!

Tidak masalah, saya berfikir sendiri, "Saya mempunyai seluruh perpustakaan Rangkaian Pembangun Perisian Microsoft dalam CD dengan penyusun C saya; Saya akan melakukan carian pantas pada kata kunci 'port COM'."

Pencarian menghasilkan banyak rujukan untuk Model Objek Komponen Microsoft (juga disebut COM), dan juga merujuk kepada MSComm. MSComm adalah kelas C ++ yang disediakan oleh Microsoft untuk bercakap dengan port bersiri. Saya melihat contohnya dan terkejut dengan berapa banyak kod yang diperlukan untuk melakukan perkara mudah seperti menulis bait ke port bersiri pada 110 baud. Yang saya mahu lakukan hanyalah membuka port bersiri yang sudah terkutuk, menetapkan kadar baudnya, dan memasukkan beberapa bait ke bawah - tidak membuat kelas baru aplikasi yang disempurnakan komunikasi bersiri!

Duduk di depan monitor saya adalah reseptor Blue Dot untuk Java Ring saya, dan saya berfikir sendiri, "Aha! Orang-orang di Dallas Semiconductor telah mengetahui cara bercakap dengan port bersiri di PC. Mari lihat apa yang mereka lakukan. " Setelah melihat kod sumber syarikat untuk Win32, jelas bahawa bercakap dengan port bersiri tidak akan menjadi tugas yang mudah.

Java untuk menyelamatkan

Pada ketika ini pada hujung minggu saya, saya berfikir mungkin akan menyeret salah satu mesin Unix saya ke makmal untuk membuat kod program di atasnya dan bukannya menggunakan apa yang sudah saya miliki. Kemudian saya teringat pengalaman saya dengan Java Ring dan pakej java.comm dari Sun. Saya memutuskan untuk mengejar jalan itu.

Apa yang disediakan oleh java.comm?

Java Communications API - atau java.comm - menyediakan kaedah bebas platform untuk mengakses port bersiri dan selari dari Java. Seperti API Java lain seperti JFC, JDBC, dan Java 3D, tahap pengarahan tertentu dipaksa pada pengaturcara untuk mengasingkan idea platform "port serial" dari model pengaturcaraan. Dalam kes reka bentuk javax.comm, item seperti nama peranti, yang berbeza dari platform ke platform, tidak pernah digunakan secara langsung. Ketiga-tiga antara muka API menyediakan akses bebas platform ke port bersiri dan selari. Antaramuka ini menyediakan panggilan kaedah untuk menyenaraikan port komunikasi yang tersedia, mengawal akses bersama dan eksklusif ke port, dan mengawal ciri port tertentu seperti baud rate, parity generasi, dan aliran kawalan.

Ketika saya melihat contoh SimpleWrite.java dalam dokumentasi, dan membandingkan 40 baris kodnya dengan 150 hingga 200 baris kod yang saya cari dalam tulisan C, saya tahu penyelesaiannya sudah ada.

Pengambilan tahap tinggi untuk pakej ini adalah kelas javax.comm.CommPort. The CommPortkelas mentakrifkan jenis perkara yang anda biasanya akan melakukan dengan pelabuhan, yang termasuk mendapat InputStreamdan OutputStreamobjek yang berada di saluran I / O untuk pelabuhan. TheCommPortkelas juga merangkumi kaedah untuk mengawal ukuran buffer dan menyesuaikan bagaimana input dikendalikan. Oleh kerana saya tahu kelas-kelas ini menyokong protokol Dallas Semiconductor One-Wire (protokol yang melibatkan perubahan dinamik dalam kadar baud, dan ketelusan sepenuhnya kepada bait yang dipindahkan), saya tahu API javax.comm harus fleksibel. Yang mengejutkan adalah betapa ketatnya kelas: Mereka mempunyai fleksibiliti yang cukup untuk menyelesaikan tugas dan tidak perlu lagi. Terdapat sedikit atau tidak perlu bloatware dalam bentuk "kaedah kemudahan" atau sokongan protokol modem seperti Kermit atau 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) { ... } 

Setelah inisialisasi, anda mempunyai kod untuk kaedah newState, seperti yang ditunjukkan di atas, yang melacak isi pita kertas (sama ada maklumat alamat atau maklumat pengaturcaraan). Kaedah di atas juga mencetak mesej untuk setiap lokasi memori pada PDP-8 yang diinisialisasi.

Seterusnya anda mempunyai mainkaedah, yang ditunjukkan di bawah; ia membuka fail dan membacanya. Kemudian kod membuka port bersiri dan menetapkan parameter komunikasi.