1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-02-20 14:54:31 +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;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import static processing.app.I18n.format;
import static processing.app.I18n.tr;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import static processing.app.I18n.format;
import static processing.app.I18n.tr;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
public class Serial implements SerialPortEventListener {
@ -53,11 +52,8 @@ public class Serial implements SerialPortEventListener {
private SerialPort port;
private CharsetDecoder bytesToStrings;
private static final int IN_BUFFER_CAPACITY = 128;
private static final int OUT_BUFFER_CAPACITY = 128;
private ByteBuffer inFromSerial = ByteBuffer.allocate(IN_BUFFER_CAPACITY);
private CharBuffer outToMessage = CharBuffer.allocate(OUT_BUFFER_CAPACITY);
private PipedOutputStream decoderInRaw;
private InputStreamReader decoderOutputUTF8;
public Serial() throws SerialException {
this(PreferencesData.get("serial.port"),
@ -189,42 +185,18 @@ public class Serial implements SerialPortEventListener {
public void processSerialEvent(byte[] buf) {
int next = 0;
// This uses a CharsetDecoder to convert from bytes to UTF-8 in
// a streaming fashion (i.e. where characters might be split
// over multiple reads). This needs the data to be in a
// ByteBuffer (inFromSerial, which we also use to store leftover
// incomplete characters for the nexst run) and produces a
// CharBuffer (outToMessage), which we then convert to char[] to
// pass onwards.
// Note that these buffers switch from input to output mode
// using flip/compact/clear
while (next < buf.length || inFromSerial.position() > 0) {
do {
// This might be 0 when all data was already read from buf
// (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();
int max = buf.length;
char chars[] = new char[512];
try {
while (next < max) {
int w = Integer.min(max - next, 128);
decoderInRaw.write(buf, next, w);
next += w;
int n = decoderOutputUTF8.read(chars);
message(chars, n);
}
} catch (IOException e) {
e.printStackTrace();
}
}
@ -295,10 +267,13 @@ public class Serial implements SerialPortEventListener {
* before they are handed as Strings to {@Link #message(char[], int)}.
*/
public synchronized void resetDecoding(Charset charset) {
bytesToStrings = charset.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.replaceWith("\u2e2e");
try {
decoderInRaw = new PipedOutputStream();
decoderOutputUTF8 = new InputStreamReader(new PipedInputStream(decoderInRaw), charset);
} catch (IOException e) {
// Should never happen...
e.printStackTrace();
}
}
static public List<String> list() {