Can't I use RXTX? Is there an alternative?

Serial communication after a long absence

After a long time, I decided to use Java for serial communication, so I did a lot of research. It's been a while since I've written a program in Java, and in the past there was only RXTX for Java serial communication, but now it's a successor or an alternative, and such articles were listed in the search. Below are the top three articles from a Google search for "Java Serial Communication".

  1. Let's use serial communication with Java http://web.sfc.wide.ad.jp/~tinaba/tutorials/serial-j/index.html
  2. Issues and alternative research of Java serial communication library RXTX https://qiita.com/kyosho/items/fc0c40458385c7d98232
  3. Software Engineering / Java Serial Communication <https://www.torutk.com/projects/swe/wiki/Java%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB % E9% 80% 9A% E4% BF% A1> The first one is how to use RXTX, and the next and the next are suggestions for alternative libraries.

Com0com as a preparatory work

Install the Null-modem emulator (https://sourceforge.net/projects/com0com/) as a COM port for the monitor. There are many articles that it may not be possible to install on Windows 10 (64bit), but here (Windows 10 Home 64bit) I was able to install without any problems. By the way, the development environment was "Eclipse 2020 (Windows 64bit version)" of Pleiades All In One and "Full Edition" of "Platform", and only JDT was additionally installed. The familiar "Tera Term" is used for the COM monitor terminal.

Can you substitute

Here, I tried the following four tests, but in my environment (Windows 10 Home), I could not "output characters with PrintWriter etc. (send)" and "receive character input from the terminal with Event (event reception)" It was only RXTX. But none are perfect. I have not tried polling reception.

  1. RXTX [http://fizzed.com/oss/rxtx-for-java]
  2. jSerialComm [http://fazecast.github.io/jSerialComm/]
  3. jpurejavacomm [http://www.sparetimelabs.com/purejavacomm/purejavacomm.php]
  4. jssc [https://github.com/scream3r/java-simple-serial-connector]

Try RXTX for the first time in a while

I brought "mfz-rxtx-2.2-20081207-win-x64.zip" from the site shown above. You are asked to put the dll under the bin or put the jar in lib \ ext, but since there is no folder called lib / ext in openjdk11, the jar was added to the library by "Add external archive" in the Eclipse build path. The dll has jre / bin under the Eclipse folder, so I thrust it there. Although the import statement is omitted, the class declaration, interface, and main function (add the throws statement because try / catch is troublesome) are as follows. It's about the same when using others.

public class RXTXtest implements SerialPortEventListener {
	public static void main(String[] args) throws Exception {
		new RXTXtest();
	}
	...(Omission)
}

The constructor and the first process are as follows. A list of COM ports that can be accessed by Enumeration is displayed. It can be displayed without any problem.

	String name;
	SerialPort port;
	RXTXtest() throws Exception {
		name=this.getClass().getSimpleName();
		Enumeration<CommPortIdentifier> ids=CommPortIdentifier.getPortIdentifiers();
		while(ids.hasMoreElements()) {
			CommPortIdentifier id=(CommPortIdentifier)ids.nextElement();
			System.out.println(id.getName());
		}
	...Omission
	}

When I actually opened the COM port and tried to write with PrintWriter (send function), a Fatal Error appeared. "COM7 & COM8" is paired in com0com, and if you connect to "COM8" side with Tera Term and "not", no error will occur, but if you connect and monitor, you will get a FATAL ERROR. It was okay before flush (), but when flush () it becomes FATAL.

		CommPortIdentifier id=CommPortIdentifier.getPortIdentifier("COM7");
		SerialPort port=(SerialPort) id.open(name, 2000);
		port.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
		port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
		port.addEventListener(this);
		PrintWriter pw=new PrintWriter(port.getOutputStream());
		pw.println(name+": "+"Tested!");
		pw.flush();

The full FATAL ERROR is included for reference. What should I do like this?

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000180004465, pid=4480, tid=4852
#
# JRE version: OpenJDK Runtime Environment (11.0.7+10) (build 11.0.7+10)
# Java VM: OpenJDK 64-Bit Server VM (11.0.7+10, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# C  [rxtxSerial.dll+0x4465]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\Users\akira\Documents\workspace\SerialTesting1\hs_err_pid4480.log
#
# If you would like to submit a bug report, please visit:
#   https://github.com/AdoptOpenJDK/openjdk-support/issues
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

Try jSerialComm

I brought "jSerialComm-2.6.2.jar" from the "jar" button at the top of http://fazecast.github.io/jSerialComm/. Also put this in the build path in "Add External Archive". The area around the constructor is as follows. Since the interface was written during processing following the sample source, it is not declared at the beginning.

public class JSerialCommTest {
	public static void main(String[] args) throws Exception {
		new JSerialCommTest();
	}
	...Omission
}

An array of available ports is shown. Intuitive but not smart. In addition, the special pair ports "CNCA0" and "CNCB0" of com0com that should be hidden are also listed (it did not appear in RXTX).

	SerialPort port;
	String name;
	JSerialCommTest() throws Exception {
		name=this.getClass().getSimpleName();
		SerialPort[] ports=SerialPort.getCommPorts();
		for(int i=0;i<ports.length;i++) System.out.println(ports[i].getSystemPortName());
		...Omission
	}

I was able to open and output without any problems. It can be transmitted at least unilaterally (on RXTX, pw.flush () spits FATAL).

		port=SerialPort.getCommPort("COM7");
		port.setComPortParameters(9600, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
		port.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);
		port.openPort();
		PrintWriter pw=new PrintWriter(port.getOutputStream());
		pw.println(name+": Tested!");
		pw.flush();

The problem is the receiving side. When monitoring an event while waiting for input in an infinite loop as shown below, an exception occurs or there is no response. The exception was related to TimeOut, but I couldn't solve it well due to lack of ability.

		port.addDataListener(new SerialPortDataListener() {
			public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_AVAILABLE; }
			public void serialEvent(SerialPortEvent event) {
				if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE) return;
				byte[] newData = new byte[port.bytesAvailable()];
				int numRead = port.readBytes(newData, newData.length);
				pw.println("Read " + numRead + " bytes.");
			}
		});
		while(true) {}

Try jpurejavacomm

The old man is already tired. Next, let's use jpurejavacomm. I brought "purejavacomm-1.0.3.jar" from the bin folder of https://github.com/nyholku/purejavacomm. It seems that this alone will not work, so I also needed "jna.jar". It's under the dist folder here https://github.com/java-native-access/jna. The class definition is almost the same as the others. Again, the interface is anonymous and written during processing, so there are no implements.

public class JPureJavaCommTest  {
	public static void main(String[] args) throws Exception {
		new JPureJavaCommTest();
	}
	...Omission
}

Constructor-Listing available ports was done normally. So far, there is no problem with any library.

	SerialPort port;
	String name;
	JPureJavaCommTest() throws Exception {
		name=this.getClass().getSimpleName();
		Enumeration<CommPortIdentifier> e=CommPortIdentifier.getPortIdentifiers();
		while(e.hasMoreElements()) {
			CommPortIdentifier id=(CommPortIdentifier)e.nextElement();
			System.out.println(id.getName());
		}
		...Omission
	}

From opening the port to checking the sending function, it ended without any problems. RXTX didn't work, but jSerialComm was good so far.

		CommPortIdentifier id=CommPortIdentifier.getPortIdentifier("COM7");
		port=(SerialPort)id.open(name,2000);
		port.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
		port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
	
		PrintWriter pw=new PrintWriter(port.getOutputStream());
		pw.println(name+": Tested!");
		pw.flush();

Well, there is no reaction when it comes to event reception. No errors or exceptions. Apparently something is wrong with it?

		port.notifyOnDataAvailable(true);
		port.addEventListener(new SerialPortEventListener() {
			public void serialEvent(SerialPortEvent arg0) {
				pw.println(name+": SerialEvent!");
			}});
		while(true) {}

I'll try jssc

it's over now. You can send serially with java, but you can't receive it !! But finally, try jssc! I dropped "jssc-2.9.2.jar" from here https://github.com/java-native/jssc/releases, but when I tried using it for a while, it looked like NG, so the previous " I used "jssc-2.9.1.jar" (because the foreigner wrote that it was an error that did not appear in the previous version, isn't it a bug?). At this point, I'm in the mood to give up. Moreover, "native-lib-loader-2.3.4.jar", "slf4j-api-1.7.30.jar" and "slf4j-simple-1.7.30.jar" are also required. What is Maven? I don't know ... The class definition is as follows. For some reason, "new SerialPortEventListener ()" cannot be done during processing (is there a constructor?), So I added it with the implements statement.

public class JSSCtest  implements SerialPortEventListener {
	public static void main(String[] args) throws Exception {
		new JSSCtest();
	}
	...Omission
}

You can also list the available ports normally. Well, I could even make RXTX. This returns a String [] array instead of Enumuration. It doesn't suit my hobby, but it's simple. However, "CNCA0" and "CNCB0" that should be hidden (these do not appear in the device manager) are also listed here. It is meaningful to set line.separator to the character ls here.

	SerialPort port;
	String ls;
	JSSCtest() throws Exception {
		ls=System.getProperty("line.separator");
		String[] ports = SerialPortList.getPortNames();
		for(int i = 0; i < ports.length; i++) {
		   System.out.println(ports[i]);
		}
		...Omission
	}

You can open and send ports without any problems, but for some reason you can't get OutputStream and you have to use a method such as writeString. I used the character ls because I couldn't break the line properly (the content is System.geyProperty ("line.separator")), but you may set it so that \ n can be received on the Tera Term side.

		port=new SerialPort("COM7");
		port.openPort();
		port.setParams(SerialPort.BAUDRATE_9600,SerialPort.DATABITS_8, SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
		port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
		port.writeString("JSSC Test!"+ls);

		port.addEventListener(this);
		while(true) {}

Now, regarding the reception of the problem, in conclusion, the event could occur, but the contents to be received are not clear.

	public void serialEvent(SerialPortEvent arg0) {
		try {
			byte[] bs=port.readBytes();
			System.out.println(bs);
		} catch (SerialPortException e) {
			e.printStackTrace();
		}
	}

If you manually enter "aaabb" from Tera Term, the following will be returned. It's easy to understand with one character and one event, but what is it?

[B@1df7e046
[B@19c87720
[B@5ccaea7d
[B@4f8bbf28
[B@6d5c934f

Conclusion

  1. RXTX throws a FATAL ERROR. I'm sorry. It is no longer maintained and is in storage!
  2. jSerialComm is unstable. Unresponsive or throwing exceptions. Do you want to work harder?
  3. jpurejavacomm does not respond to event reception. Is it bad to use?
  4. jssc may be able to do something about it. It is necessary to scrutinize the received contents.

Recommended Posts

Can't I use RXTX? Is there an alternative?
How to use Maven that I can't hear anymore
Is there an instance even if the constructor fails?
I tried to solve the Ruby karaoke machine problem (there is an example of the answer)
I tried to solve the Ruby bonus drink problem (there is an example of the answer)