1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-02-21 15:54:39 +01:00

Use InputStreamReader for serial UTF8 decoder

The implementation is much more straightforward.

It should also solve a JDK incompatiblity:

  java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;
  at processing.app.Serial.serialEvent(Serial.java:185)
  at jssc.SerialPort$LinuxEventThread.run(SerialPort.java:1299)

See #8903
This commit is contained in:
Cristian Maglie 2020-04-06 13:14:34 +02:00
parent 5adf408270
commit 2162966924

View File

@ -22,23 +22,22 @@
package processing.app; package processing.app;
import jssc.SerialPort; import static processing.app.I18n.format;
import jssc.SerialPortEvent; import static processing.app.I18n.tr;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.io.InputStreamReader;
import java.nio.CharBuffer; import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import static processing.app.I18n.format; import jssc.SerialPort;
import static processing.app.I18n.tr; import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
public class Serial implements SerialPortEventListener { public class Serial implements SerialPortEventListener {
@ -53,11 +52,8 @@ public class Serial implements SerialPortEventListener {
private SerialPort port; private SerialPort port;
private CharsetDecoder bytesToStrings; private PipedOutputStream decoderInRaw;
private static final int IN_BUFFER_CAPACITY = 128; private InputStreamReader decoderOutputUTF8;
private static final int OUT_BUFFER_CAPACITY = 128;
private ByteBuffer inFromSerial = ByteBuffer.allocate(IN_BUFFER_CAPACITY);
private CharBuffer outToMessage = CharBuffer.allocate(OUT_BUFFER_CAPACITY);
public Serial() throws SerialException { public Serial() throws SerialException {
this(PreferencesData.get("serial.port"), this(PreferencesData.get("serial.port"),
@ -189,42 +185,18 @@ public class Serial implements SerialPortEventListener {
public void processSerialEvent(byte[] buf) { public void processSerialEvent(byte[] buf) {
int next = 0; int next = 0;
// This uses a CharsetDecoder to convert from bytes to UTF-8 in int max = buf.length;
// a streaming fashion (i.e. where characters might be split char chars[] = new char[512];
// over multiple reads). This needs the data to be in a try {
// ByteBuffer (inFromSerial, which we also use to store leftover while (next < max) {
// incomplete characters for the nexst run) and produces a int w = Integer.min(max - next, 128);
// CharBuffer (outToMessage), which we then convert to char[] to decoderInRaw.write(buf, next, w);
// pass onwards. next += w;
// Note that these buffers switch from input to output mode int n = decoderOutputUTF8.read(chars);
// using flip/compact/clear message(chars, n);
while (next < buf.length || inFromSerial.position() > 0) { }
do { } catch (IOException e) {
// This might be 0 when all data was already read from buf e.printStackTrace();
// (but then there will be data in inFromSerial left to
// decode).
int copyNow = Math.min(buf.length - next, inFromSerial.remaining());
inFromSerial.put(buf, next, copyNow);
next += copyNow;
inFromSerial.flip();
bytesToStrings.decode(inFromSerial, outToMessage, false);
inFromSerial.compact();
// When there are multi-byte characters, outToMessage might
// still have room, so add more bytes if we have any.
} while (next < buf.length && outToMessage.hasRemaining());
// If no output was produced, the input only contained
// incomplete characters, so we're done processing
if (outToMessage.position() == 0)
break;
outToMessage.flip();
char[] chars = new char[outToMessage.remaining()];
outToMessage.get(chars);
message(chars, chars.length);
outToMessage.clear();
} }
} }
@ -295,10 +267,13 @@ public class Serial implements SerialPortEventListener {
* before they are handed as Strings to {@Link #message(char[], int)}. * before they are handed as Strings to {@Link #message(char[], int)}.
*/ */
public synchronized void resetDecoding(Charset charset) { public synchronized void resetDecoding(Charset charset) {
bytesToStrings = charset.newDecoder() try {
.onMalformedInput(CodingErrorAction.REPLACE) decoderInRaw = new PipedOutputStream();
.onUnmappableCharacter(CodingErrorAction.REPLACE) decoderOutputUTF8 = new InputStreamReader(new PipedInputStream(decoderInRaw), charset);
.replaceWith("\u2e2e"); } catch (IOException e) {
// Should never happen...
e.printStackTrace();
}
} }
static public List<String> list() { static public List<String> list() {