Skip to content

Commit 2162966

Browse files
committed
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
1 parent 5adf408 commit 2162966

File tree

1 file changed

+30
-55
lines changed

1 file changed

+30
-55
lines changed

arduino-core/src/processing/app/Serial.java

+30-55
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,22 @@
2222

2323
package processing.app;
2424

25-
import jssc.SerialPort;
26-
import jssc.SerialPortEvent;
27-
import jssc.SerialPortEventListener;
28-
import jssc.SerialPortException;
25+
import static processing.app.I18n.format;
26+
import static processing.app.I18n.tr;
2927

3028
import java.io.IOException;
31-
import java.nio.ByteBuffer;
32-
import java.nio.CharBuffer;
29+
import java.io.InputStreamReader;
30+
import java.io.PipedInputStream;
31+
import java.io.PipedOutputStream;
3332
import java.nio.charset.Charset;
34-
import java.nio.charset.CharsetDecoder;
35-
import java.nio.charset.CodingErrorAction;
3633
import java.nio.charset.StandardCharsets;
3734
import java.util.Arrays;
3835
import java.util.List;
3936

40-
import static processing.app.I18n.format;
41-
import static processing.app.I18n.tr;
37+
import jssc.SerialPort;
38+
import jssc.SerialPortEvent;
39+
import jssc.SerialPortEventListener;
40+
import jssc.SerialPortException;
4241

4342
public class Serial implements SerialPortEventListener {
4443

@@ -53,11 +52,8 @@ public class Serial implements SerialPortEventListener {
5352

5453
private SerialPort port;
5554

56-
private CharsetDecoder bytesToStrings;
57-
private static final int IN_BUFFER_CAPACITY = 128;
58-
private static final int OUT_BUFFER_CAPACITY = 128;
59-
private ByteBuffer inFromSerial = ByteBuffer.allocate(IN_BUFFER_CAPACITY);
60-
private CharBuffer outToMessage = CharBuffer.allocate(OUT_BUFFER_CAPACITY);
55+
private PipedOutputStream decoderInRaw;
56+
private InputStreamReader decoderOutputUTF8;
6157

6258
public Serial() throws SerialException {
6359
this(PreferencesData.get("serial.port"),
@@ -189,42 +185,18 @@ public synchronized void serialEvent(SerialPortEvent serialEvent) {
189185

190186
public void processSerialEvent(byte[] buf) {
191187
int next = 0;
192-
// This uses a CharsetDecoder to convert from bytes to UTF-8 in
193-
// a streaming fashion (i.e. where characters might be split
194-
// over multiple reads). This needs the data to be in a
195-
// ByteBuffer (inFromSerial, which we also use to store leftover
196-
// incomplete characters for the nexst run) and produces a
197-
// CharBuffer (outToMessage), which we then convert to char[] to
198-
// pass onwards.
199-
// Note that these buffers switch from input to output mode
200-
// using flip/compact/clear
201-
while (next < buf.length || inFromSerial.position() > 0) {
202-
do {
203-
// This might be 0 when all data was already read from buf
204-
// (but then there will be data in inFromSerial left to
205-
// decode).
206-
int copyNow = Math.min(buf.length - next, inFromSerial.remaining());
207-
inFromSerial.put(buf, next, copyNow);
208-
next += copyNow;
209-
210-
inFromSerial.flip();
211-
bytesToStrings.decode(inFromSerial, outToMessage, false);
212-
inFromSerial.compact();
213-
214-
// When there are multi-byte characters, outToMessage might
215-
// still have room, so add more bytes if we have any.
216-
} while (next < buf.length && outToMessage.hasRemaining());
217-
218-
// If no output was produced, the input only contained
219-
// incomplete characters, so we're done processing
220-
if (outToMessage.position() == 0)
221-
break;
222-
223-
outToMessage.flip();
224-
char[] chars = new char[outToMessage.remaining()];
225-
outToMessage.get(chars);
226-
message(chars, chars.length);
227-
outToMessage.clear();
188+
int max = buf.length;
189+
char chars[] = new char[512];
190+
try {
191+
while (next < max) {
192+
int w = Integer.min(max - next, 128);
193+
decoderInRaw.write(buf, next, w);
194+
next += w;
195+
int n = decoderOutputUTF8.read(chars);
196+
message(chars, n);
197+
}
198+
} catch (IOException e) {
199+
e.printStackTrace();
228200
}
229201
}
230202

@@ -295,10 +267,13 @@ public void setRTS(boolean state) {
295267
* before they are handed as Strings to {@Link #message(char[], int)}.
296268
*/
297269
public synchronized void resetDecoding(Charset charset) {
298-
bytesToStrings = charset.newDecoder()
299-
.onMalformedInput(CodingErrorAction.REPLACE)
300-
.onUnmappableCharacter(CodingErrorAction.REPLACE)
301-
.replaceWith("\u2e2e");
270+
try {
271+
decoderInRaw = new PipedOutputStream();
272+
decoderOutputUTF8 = new InputStreamReader(new PipedInputStream(decoderInRaw), charset);
273+
} catch (IOException e) {
274+
// Should never happen...
275+
e.printStackTrace();
276+
}
302277
}
303278

304279
static public List<String> list() {

0 commit comments

Comments
 (0)