Common problem
Javacomm and RXTX have some different things when installing. It is strongly recommended to install a little installation in accordance with the installation instructions. If the installation instructions require a jar file or a shared library must be under a specific folder, which means that it needs to be taken seriously. If a specific file or device needs to have a specific ownership or access right, it also means that it needs to be dealt with seriously. Many installation issues are caused by not in accordance with the requirements of the installation instructions.
It should be noted that some versions of JavaComm will have two installation instructions. One is used for Java 1.2 and later, one for Java 1.1 version. Using the wrong installation instructions will cause the installation result that cannot be worked. On the other hand, some versions/components/packages of TXTX will contain incomplete descriptions. In this case, it is necessary to obtain the source code published by RXTX, which contains complete installation instructions.
In addition, it should be noted that the JDK installation program of Windows will contain three Java virtual machines, so there will be three extended folders.
What's more, even the fourth JRE, which exists in the directory structure of/Windows. JavaComm should be installed in JDK and all public JRE as extensions.
Webstart
Javacomm
A common problem about Javacomm and RXTX is that they do not support installation through Java WebStart: Javacomm's infamous is because you need to call a file called javax.com.properties to the JDK LIB directory, and this cannot be via Java WebStart Completed. It is very frustrating that the need for this file is some unnecessary designs in Javacomm, and the designers of Javacomm can easily avoid this. Sun stubbornly rejected the error, and they emphasized that this mechanism is essential. They were talking nonsense, especially when they mentioned Javacomm, because Java had a service provider architecture that specializes in such intentions for a long time.
There is only one line in the content of this attribute file, which provides a local -driven Java class name.
driver = com.sun.win.win32driver
The following is a technique that can deploy javacomm through Web Start to ignore the attribute file that hurts the brain. But it has serious defects and may fail when deploying a newer Javacomm -if Sun will make a new version.
First, turn off the Security Manager. Some stupid programmers of Sun felt that the existence of the terrible javax.comm.properties files was cool over and over again, especially after it was first loaded. This just checks whether the file exists without other reasons.
System.setSecurityManager (NULL);
Then, when the Javacomm API was originally originally started, manually initialized the driver.
String drivename = "com.sun.comm.win32driver"; // or get as a jnlp proprtemCommdriver Commdriver = (Commdriver) class.FORNAME (DriverName) .NewInstance (). ; Commdriver.initialize ();
RXTX
RXTX needs to change the ownership and access right of the serial device on some platforms. This is also a thing that cannot be done through WebStart.
When the program starts, you should ask users to perform the necessary settings as super users. In particular, RXTX has a mode matching algorithm to verify the "legal" serial equipment name. When someone wants to use non-standard devices, such as USB-to-Serial Converter, this often messs things. This mechanism can be blocked by system attributes. For details, refer to the installation instructions of RXTX.
Javacomm API
introduction
Java's official serial communication API is Javacomm API. This API is not part of the Java 2 standard version, so the implementation of this API needs to be downloaded separately. Unfortunately, Javacomm did not get enough attention to Sun, and the actual maintenance time was not very long. Sun just repaired some unimportant bugs occasionally, but did not do some important maintenance that has long expired.
This section explains the basic operation of the Javacomm API. The source code provided is simplified to display the focus, and it needs to be improved in practical applications.
The source code of this chapter is not the only available example code. Many examples contain javacomm downloads. These examples include more information about how to use it than its API documents. Unfortunately, Sun has no real tutorial or some explanation documents. Therefore, to understand the mechanism of this API, learning these examples is worth it, and you still need to learn this API document. But the best way is to learn these examples and use them. Due to the lack of easy -to -use applications and understanding of the programming model of these APIs, APIs are usually attacked. Compared to its reputation and function, this API is better, but that's just.
The API uses a callback mechanism to notify the programmer's new data. This is also a good idea to learn this mechanism, rather than relying on the inquiry port. Unlike other callback interfaces in Java (such as: in the graphic interface), this interface allows only one monitor to listen. If multiple listeners request a few incidents, the main monitoring device must be implemented by distributing information to other secondary listeners.
Download and installation
download
Sun's JavaComm webpage points to the download address. Under this address, Sun currently (2007) provides Javacom 3.0 version that supports Solaris/Sparc, Solaris/X86 has already linux X86. Downloads requires a account of a SUN company. The download page provides a link to the registration page. The purpose of registration is not clear. When registering, users can download JDK and JRES, but for these almost trivial Javacomm, Sun Company quoted legal provisions and government restrictions on software distribution and exports.
The official no longer provides the Windows version of Javacomm, and Sun has violated their own product death strategy -cannot be downloaded in Java products. But you can still download the Windows version of 2.0 from this (Javacom 2.0).
Install
Installation with the installation instructions with download. Some versions of JavacomM 2.0 will include two installation instructions. The most obvious difference between these two descriptions is that the wrong one is used in the ancient Java1.1 environment, and the one suitable for Java 1.2 (JDK1.2.html) is correct.
Windows users may not realize that they have installed the copy of the same VM in different places (usually 3 to 4). Some IDE and Java applications may also bring their own private JRE/JDK. Therefore, Javacomm needs to be installed repeatedly to these VM (JDK and JRE) so that in order to develop and execute serial applications.
IDE has a representative IDE way to learn a new library (class and document). Usually a library that JavaComm not only needs to be identified by the IDE, but also each project using the library should also be identified. Reading the IDE document, you should pay attention to the old version of the old JavacomM 2.0 and the Javadoc API documentation use the Java 1.0 Java DOC layout. Some modern IDEs no longer know these structures and cannot integrate JavacomM2.0 documents into their help systems. In this case, an external browser is needed to read documents (recommended activities)
Once the software is installed, it is recommended to test samples and Javadoc directory. It makes sense to build and run sample applications to confirm whether the installation is correct. The sample program usually requires some small adjustments to run on a special platform (like the COM port identifier that rewritten hard codes). When running a sample program, it is best to have some serial hardware. I want to cabling.
Serial_programming: RS-232 Connections and Serial_programming: Modems and at Commands provides some information about how to build a serial application development environment.
Find the expected serial port
The first three things to be done when using Javacomm serial programming
The port logo of enumeration and selection expectations is completed in the same cycle:
Import javax.comm.*; Import Java.util.*; ... /////platform spiecific port name, here = a unix name //// note: On at Least One Unix Implementation vacomm // enumerates the ports As "com1" ... "comx", too, and not // by their unix device names "/dev/tty ...". //yet another good rea and hard-code the waitd, but, but, but Instead Make It User Configurable.//string WANTEDPORTNAME = "/DEV/TTYA"; ///// Get An Enumeration of All Ports Known to Javacomm // ENUMERATION = CommptionIdIdifier.GetPortIdIdifiers (); ///// Check Each Port Identifier if // (A) It Indicates a Serial (Not a Parallel) Port, and // (B) Matches the design name.//commPortidentifier portid = null; // Will be set if foundwhile TIDENTIFIERS.hasmoreements ()) {CommptionIdifier Pid = (CommptionIdifier) portablentifiers.nextElement (); if (pid.getporttype () == CommportIdifier.Port_Serial &&GetName ( ).equals (WANTEDPORTNAME)) {Portid = Pid; Break;}} if (Portid = = null){ System.err.println("Could not find serial port " + wantedPortName); System.exit(1);}//// Use port identifier for acquiring the port//...注意:JavaComm会从Get a default accessible serial logo list in the driver related to a specific platform that is bound. This list cannot actually be configured through JavaComm. Methods CommptIdifier.addPortName () are misleading, because the driver class is related to the platform, and their implementation is not part of the public API. Relying on the driver, this port list may be configured/extended in the driver. Therefore, if Javacomm does not find a certain port, some changes to the driver will sometimes help. Once a certain port identifier is found, you can use it to obtain the expected port: ////////////////////////////0 use port identifier for account // Serialport port = null; try {port = (serverport) portid.open ("name", // name of the application asking for the port 10000 // wait max. 10 sec. To acquire port); " + e); System. EXIT (1);} //////////////////////// now we are granted explusive access to the particular service // port.
Initialization serial port
The initialization of the serial port is very intuitive. You can set the communication parameters (Potter rate, data bit, stop bit, and puppet verification) one by one. You can also use the convenient setSerialportparams (...) method to get them.
As a part of initialization, the input and output stream of communication can be configured in the following example.
Import Java.io.*; ... //// Set All the Params. // This May Need to go in a try/Catch Block Which Throws OrtaRAMS (115200, Serialport.databits_8, Serialport.stopbits_1 , Serialport.parity_none); ////// Open The Input Reader and Output Stream. l Application. Typically One Would Use Streams in // Both Directions, SINCE TheY Alow for Binary Data Transfer, // Not only Character Data Transfer.//bufferedReader is = null; // for demo Purposes only. typical.printstream os = null; try {is = new bufferedReader (New InputStreamReader (Port.getinputStream ()));} Catch (IOEXCEPTION E) {System.err.println ("CAN'TENPUT Stream: write- only"); New linux Systems Relying UNICODE, so it might be needssary to // Specify the Encoding Scheme to be used. ), or iso Latin 1 (8 bit // communication), as there is likely no model out theree accepting // unicode for its commit. putstream (), true, "ISO-8859-1" ); // OS = New Printstream (port.getoutPutstream (), true); //// Actual Data Communication WOULD HAPPEN Here // PerformreadwriteCode (); /////////////////////////it Is very. tant to close input and output streams As well // as the port. Otherwise java, driver and os: ! = Null) port.close (); Simple data transmission simply write data
Writing the data into the serial port is as simple as the basic Java IO. But there are still some precautions when you use the AT HAYES protocol:
Clipboard
To do:
Explain how to mix the input and output of binary and characters in the same stream
Modify the sample program to use the flow
// Write to the output os.print("AT");os.print("/r/n"); // Append a carriage return with a line feedis.readLine(); // First read will contain the echoed Command you sent to it. in this case: "at" is.reamline (); // Second Read Will Remove the Exhibition Feed that at generals as outputSimple data reading (rotation)
If you use the writing operation correctly (as described above), you only need a simple command.
// Read the responsestring response = is.Readline (); // if you stand "then response ==" OK "
Simple reading and writing questions
The simple serial reading and writing demonstrated in the previous section has very serious defects. All operations are done by blocking I/O. This means that when there is no readable data, or the output buffer is full (the device cannot accept more data):
Reading and writing method (in the previous example is os.print () or is.Readline ()) will not return, causing the application to be suspended. More precisely, the reading and writing threads are blocked. If that thread is the main thread of the application, the application will stop until the blocking conditions are released (that is, readable data to reach or the device is re -received).
Unless the application is the most primitive, the program is blocked. For example, at least it must allow users to cancel communication operations. This requires the use of non -blocking I/O or asynchronous I/O. However, JavaComm is based on the standard I/O system (InputStream, OutputStream), but can use a deformation technique displayed later.
The so -called "deformation technique" is a limited support provided by the JavaComm to the asynchronous I/O through the incident notification mechanism. However, the common solutions to realize non -blocking I/O in Java to block I/O are threads. This solution for serial port writing operation is practical and feasible. It is strongly recommended to use a separate thread to write the serial port to write operations -although the incident notification mechanism has been used, this will be explained later.
Reading operations should also be processed in a separate thread, but it is not necessary to use the JavaComm incident notification mechanism. Summarize:
Read operation and use event notification and/or separate thread;
Use separate threads to write operations, and the event notification mechanism can be selected.
The next part will introduce some other details.
Event drive serial communication introduction
The JavaComm API provides an event notification mechanism to overcome the problems caused by blocking I/O. But this mechanism is also problematic in this typical SUN method.
In principle, an application can register an event monitor to a specific serial port to receive notifications to receive important events on this port. The two most interesting events of reading and writing data are
javax.Comm.SerialPortevent.data_available and javax.Comm.serialPortevent.output_buffer_empty.
But this also brings two questions:
Before conducting detailed discussions, the next section will demonstrate the main method of implementing and registering a serial event processor. Remember that there is only one event processor in a serial port, and it has to deal with all possible events.
Set serial event processor
Import javax.comm. *; /** * Listener to handle all Serial port events. * * Note: It is typical that the serviceporteventris is imageed AT is support to communicate with the * device. That way the listner Has Easy Access to State Information * About the Communication, Eg When A PARTICular Communication * Protocol Needs to Be Followed. RPOSES This Example Implements a * Section Class. * / Class SerialListener IMPLEMENTS SerialPorteventristener { / ** * handle Serial events. Dispatches the event to event-specific * method. * @param event the service event */ @Override Public Void Seriavent (SerialPortevent). {// // Dispatch Event to Individual Methods. This kepts this ugly // switch/ Case Statement as Short As Posses. // Switch (Event.GeteventType ()) {Case SerialPortevent.output_EMPTY: OUTPUTBUFEREMPTY (Event); BREAK; ASE SerialPortevent.data_available: DataAvailable (Event); Break; /* Other Events, Not Implemented Here -> Case SerialPortevent.bi: Breakinterrupt (Event); Break; Case SerialPortevent.cd: CarrierDetect (Event); Break; Case SerialPortevent.cts: Cleartosend (EV ENT); Bream; Case SerialPortevent.dsr: DataSetream (Event); Break; Case SerialPortevent.fe: Framingerror (Event); Break; Case SerialPortevent.oe: OverRuneror (EVENT); Break; Case SerialPortevent.pe: ParityError (Event); ak; Case SerialPortevent.ri: Ringindicator (Event); Break; <- Other Events, Not Implemented Here * /}} / ** * Handle Output Buffer Empty Events. * Note: The Reception of this event is optional and not * Guaranteeed by the AP I Specification. * @Param Event the Output Buffer EMPTY EVENT */ Protected Void OutputbuffreMPTY (SerialPortevent Event) {// Implement Wu Data Here} /** * Handle Data Available Events. * * @Param Event The Data AV AV Ailable Event */ Protected Void Dataavailable (SerialPortevent Event) {// Implement Reading from the Serial port here}} Once the listener is implemented, it can be used to monitor specific serial incidents. To do so, you need to add an instance of listening to the serial port. In addition, the receiving of each event type requires separate applications.
Serialport port = ...; ... //// Configure port parameters here. Only after the port is configured it // makes ance to endable events. event is enabled .. ../// typically, if the current class images the serviceVentListener interface // One will call ///port.addeventristener (this); a New Instance of Seriallistener is Created: // port.adDeventListener (New SerialListener ()); ///// Enable The events we are Internet e); /* Other Events Not used in this example-> port. notifyonBreakinterroup (true); port.notifyoncarrierDectEct (true); port.n OTIFYONCTS (TRUE); port.notifyondsr (true); port.notifyonframingerror (tru e); port.notifyonoverrunerror (true); port.notifyonParityerror (true); port.notifyonringicator (true);
Data writing
Data writing with separate separation is only one purpose: to avoid the entire application block locked because a serial port is not ready to write data.
A simple, thread -safe ring buffer realization
Use a thread independent of the main programline to write operations, indicating that the data that needs to be written in some way is submitted to the writing thread from the main application thread (main thread). This can use a shared asynchronous event buffer, such as a Byte array. In addition, the main program also needs some way to determine whether the data or the data buffer can be written in the data buffer. If the data buffer is full, it indicates that the serial port is not ready to write operations, and the data to be output is queuing. The main program needs to inquire new free space available in the shared data buffer. However, in the gap between the main program, you can do some other things, such as updating the user interface (GUI), providing a command prompt that can exit data, and so on.
At first glance, pipedInputStream/PipedoutPutstream is a good idea for this communication. But if the pipeline flow is really useful, then Sun is not Sun. If the corresponding pipeDoutStream is not cleaned in time, pipedInputStream will block, which will block the application thread. Even if you use independent threads, you can't avoid it. Java.nio.pipe also has the same problem as this. Its obstruction is related to the platform. It is not very good to change the traditional I/O using Javacomm to NIO.
A very simple synchronous ring buffer area is used in this article for thread data transmission. Applications in the real world are likely to use more complex buffer. For example, the realization of a real world requires an operation buffer from the perspective of input and output flow.
Such a ring buffer is not special, and there is no special attribute in thread processing. It is just a simple data structure used here to provide data buffer. The buffer has been implemented here to ensure that accessing the data structure is thread security.
/***Synchronized raing buffer.*Suitable to hand overda from one thread to another. **/public class rightbuffer {/** Internal buffer to set the data **/p **/p Rotect byte buffer []; /** SIZE of The Buffer ** / Protected Int Size; / ** Current Start of Data Area ** / Protected Int Start; / ** Current End of Data Area ** / Protected end end; Struct a Ringbuffer with a default buffer size of 1K. */ Public Ringbuffer () {this (1024);}/ ** * Constructure A Ringbuffer with a Certain buffer size. gbuffer (int size) {this.size = size; buffer = new byte [size]; clear ();} / ** * clear the buffer contents. All Data Still in the buffer is lost. * / public void clear () {// Just reset the p ointers. THE Remaining Data Fragments, if any, // Will be overwritten during normal operation. Start = end = 0;} /*** Return user in buffer. This is the size of the. * DATA CURRENTLY in the Buffer. * <p> * Note: While The value is Correct Upon Returning, IT * is not nextarily valid when data is read from the * buffer or write the buffer. Another Thread Might * have filed the buffer or emptied it in the mean time. * * @ Return CurrenTly Amount of Data Available in Buffer * / Public Int Data () {Return Start <= END? END -Start + size; ace in buffer. Note: While The Value is * Correct Upon Returning, it is not nextarily valid when * data is written to the buffer or read from the buffer. Tied * it in the mean time. * * @Return currently available Free Space Space */ Public int Free () {Return Start <= End? SIZE + Start -END: Start -End;} /** * Write As Much Data As Posses. * @Return amount of DATA Actually Written * / int Write (byte Data []) {Return Write (data, 0, data.length);} / ** * Write as a Possible to the Buffer. * @param Data Array Holding Data to be Written * @param off official of data in array * @param n amount of data to write, Starting from. * @Return of data action written */ int Write (byte D ATA [], int Office, int N) {if ( n <= 0) Return 0; int Remain = n; // @todo check if off is valid: 0 = <= off <data.Length; Throw exp Not instal ? Start: buffer.Length) -end); if (i> 0) {system.arrayCopy (data, off, buffer, end, i); off += i; remain- = i; end += i;} i = Math.min (remain, end> = start? Start: 0); if (i> 0) {system.arraycopy (data, off, buffer, 0, i); Remain- = i; end = i;} Return N -Remain;} / ** * Read as Much Data As Posses from the Buffer. * @Param Data Where to Store the Data * @Return of Data Read * / Int Read (byte Data []) {Return Read (data , 0, data.Length);} /** * Read as Much Data As Posses from the Buffer. * @Param Data where to store the read data * @param offSet of data in array * m n amount of data to Read * @Return of Data Actually Read */ int Read (byte data [], int Office lid : 0 = <= Off <data.Length; Throw Exception if not int i = Math.min (Remain, (End <start? Buffer.Length: end) -START); if (i> 0) {System.arrayCopy ( Buffer, Start, Data, OFF, I); OFF += i; Remain- = i; Start += i; if (start> = buffer.length) start = 0;} i = math.min (remain, end> = START? 0: End); if (i> 0) {System.arrayCopy (buffer, 0, data, off, i); Remain- = i; Start = i;} Return n -Remain;}}}}}By using this ring buffer, you can now submit data from one thread to another thread. Of course, other threads are safe and non -blocking methods. The key point here is that when the buffer is full or the buffer is empty, the read and write of the data will not cause blockage.
According to the outline of the event processor demonstration of the section demonstration in the "Create Serial Enterprise Processor", you can use the shared ring buffer introduced in the "simple, thread safe ring buffer" to support the output_buffer_empty event. Not all JavacomM implementation supports this event, so this code may never be called. But if it can, it is part of ensuring the best data throughput, because it can make the serial port in a state of idleness for a long time.
The outline of the event monitor needs to provide an OutputBuffRempty () method. Its implementation is as follows:
Ringbuffer DataBuffer = ...; /** * Handle Output Buffer Empty Events. * Note: The Reception is of this event is Optional and Not * Guarented by the API ATION. * @Param Event the Output Buffer Empty Event */ Protected Void outputBuff on (SerialPortevent Event) {}The following example assumes that the destination of the data is a file. When the data arrives, it will be removed from the serial port and written into the destination file. This is just a refined view, because in fact you need to check the EOF logo of the data to regulate the modem (usually called "cat") as the command mode.
Import javax.comm.*; ... inputStream is = port.getInputStream (); bufferedoutstream out = new bufferedOutstream (New FileoutStream ("Out.dat") / ** * Listen to port events */ class filelistener imageS SerialPorteventListener { / ** * handle serial event. * / Void Serialevent (SerialPortevent E) {Serialport Port = (Serialport) E.Getsource (); // // Discrimine Handling TO EVEN t Type // switch (e.Geteventtype ()) {Case SerialPortevent.data_available: // // Move All Currently available data to the file // try {int C; space ((c = is.read ()))! = -1) {out.writ (c); } } Catch (IOEXception EX) {...} Break; Case ...: ... Break; ...} if (is! = null) is.Close (); if (port! = Null) port.close ();}
Modify the demodulator control
JavaComm is mainly concerned about a serial processing and transmission of data on the serial port. It does not understand or provides support for high -level protocols, such as Hayes modulation and demodulation instructions is usually used to control customer -level cats. This is not Javacomm's task, nor is it a bug.
Like other special serial devices, if you want to control a cat with Javacomm, you must write the necessary code on Javacomm. The page "Hayes-Commposition Modems and at Commands" provides the necessary basic information to process Hayes cats.
Some operating systems, like Windows or a Linux control command to configure a special type or brand of cat control commands, provide more or less standards. For example, the "driver" of Windows cats is usually just registered entrances, describing individual cats (the real driver is a universal serial modulation driver). Javacomm cannot obtain specific data of such operating systems. Therefore, either a separate Java tool must be provided to allow users to configure an application for using individual cats, or add some corresponding platform (local) code.
RXTX
Overview and version
Since Sun did not provide Javacomm reference implementation for Linux, people have developed RXTX for Java and Linux. Later, RXTX was transplanted to other platforms. The latest version of RXTX is known to run more than 100 platforms, including Linux, Windows, Mac OS, Solaris, and other operating systems.
RXTX can be used independently of the JavaComm API, or it can also be used as a so -called Java Commum API service. If the latter uses a packaging package called JCL. JCL and RXTX are usually packed with Linux/Java, or JCL is completely integrated with the code. Therefore, before downloading them one by one, take a look at the CD of the Linux distribution version of CD.
Due to Sun's limited support and inappropriate documentation of Javacomm, he abandoned the Javacomm API and turned directly to use RXTX instead of the JCL packaging package. It seemed to have become a trend. However, RXTX's documents are very rare. In particular, RXTX developers like to make their versions and bag content a mess (such as using or unused integrated JCL). Starting from version 1.5, RXTX includes an alternative class of the public JavacomM class. Due to legal reasons, they were not in the java.pomm package, but under gui.io. However, the two existing version of the packaging content is very different.
Therefore, if you want to program the original Javacomm API
SUN JAVACOMM General Edition. When writing this article is actually the Unix package (including support for various types of Unix systems, like Linux or Solaris), even on Windows, this Unix package also needs to be used to provide universal implementation of java.Comm. Only using Java to implement that part will be used, but UNIX's local library will be ignored.
RXTX 2.0, in order to have different providers in the universal version of the Javacomm, unlike the one under the JavacomM package. However, if you just want to replace the package with gnu.io, then you only need to convert a Javacomm application into a RXTX application.
If you give up one of many members of the many members that make Javacomm that disappointed with the behavior of supporting Windows, then you should transfer your JavacomM to RXTX. As you can see above, there are two ways to complete this. Assuming you have installed a version of RXTX, then the following options can be selected: one:
The first item above has been explained earlier, and the second item is quite simple. For those who need to transplant JavacomM to RXTX 2.1, you only need to replace all the references to the "java.Comm" package in the application source code to the "GNU.IO" package. If the original JavaComm application is proper Other things need to be done.
On the Unix platform, RXTX 2.1 even provides the tool "Contrib/Changepackage.sh" to perform global replacement in the source code tree structure. Environment) to complete.