Java SerialPortEvent issue: DATA_AVAILABLE calls faster then incoming data - java

I'm posting for the first time so I hope that I write everything according to the format.
Currently I'm working on a project using Serial Communication with RXTX between a java application and a measuring device. This works great, but now I want to catch the data that the device sends with events.
The code below works but has the following issue:
DATA_AVAILABLE will be called 4 times before all the data will be send.
I catch this in a string called vBuffer and I'm able to catch the data to get the full string.
Now I want to return this data (the full string), but cannot find a SerialPortEvent that will wait till all data is send to return this string.
In the example below I use OUTPUT_BUFFER_EMPTY but this is called at the beginning of sending a command. This means that when sending the command for the 2nd time, the OUTPUT_BUFFER_EMPTY event will return vBuffer with data from the first command, and immediately after starts the 2nd command. At 3rd time OUTPUT_BUFFER_EMPTY sends the data from the 2nd command and starts the 3rd etc.
Is there a way in DATA_AVAILABLE to wait till all data is send, or is there another event that will be called after all data is send?
Extra info: A command is send with a Stringbuilder of chars to make sure the right format for the device is send. The lay-out of a command is as follows: <STX><COMMAND><RTX><CR><LF>.
Might I be able to catch the end by looking at when the command ends? If so, how?
Update: This is the code how I send a function:
StringBuilder message = new StringBuilder();
message.append(new Character((char) 2)); // STX (Start of Text)
message.append("M"); // Command character
message.append(new Character((char) 3)); // ETX (End of Text
message.append(new Character((char) 13)); // CR (Carriage Return)
message.append(new Character((char) 10)); // LF (Line Feed)
outputStream.write(message.toString().getBytes());
After this the DATA_AVAILABLE will kick in. But doesn't wait till all received data is done.
Edit: To bump this up, still not further with the problem.
serialEvent Method :
public void serialEvent(SerialPortEvent event)
{
switch (event.getEventType())
{
case SerialPortEvent.BI:
case SerialPortEvent.OE:
case SerialPortEvent.FE:
case SerialPortEvent.PE:
case SerialPortEvent.CD:
case SerialPortEvent.CTS:
case SerialPortEvent.DSR:
case SerialPortEvent.RI:
case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
if (vBuffer != "")
{
System.out.println(vBuffer);
}
break;
case SerialPortEvent.DATA_AVAILABLE:
byte[] readBuffer = new byte[40];
try
{
while (inputStream.available() > 0)
{
int numBytes = inputStream.read(readBuffer);
}
vBuffer += new String(readBuffer);
System.out.print(new String(readBuffer));
}
catch (IOException e)
{
System.out.println(e);
}
break;

I've found a way to check the command set STX and ETX too see if the message is complete (ETX is in the end of the message). If this checks true, then I've got a complete message.
Issue solved!
public void serialEvent(SerialPortEvent event)
{
if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE)
{
System.out.println("Data available event received");
try
{
int available = inputStream.available();
byte[] readBuffer = new byte[available];
if (available > 0)
{
inputStream.read(readBuffer);
}
messageBuffer = messageBuffer + new String(readBuffer);
try
{
int start = messageBuffer.indexOf(new Character((char) 2));
int end = messageBuffer.indexOf(new Character((char) 10));
if (start >= 0 && end >= 0)
{
System.out.println("We found 1 complete message!!");
System.out.println(messageBuffer.substring(start, end));
_fireBufferEvent();
messageBuffer = "";
}
}
catch (IndexOutOfBoundsException ex)
{
System.out.println("IndexOutOfBoundsException, message not complete yet. Waiting for more data.");
}
}
catch (IOException ex)
{
System.out.println("IOException while reading data:");
System.out.println(ex);
}
}

Related

loop to readline() breaks without exceptions

I'm currently trying to create an App which enables me to control an Arduino board. For some reason, whenever it gets to the stage where the server waits for a message and gets to this loop, the loop breaks without any exceptions thrown when there is no action taken.
What I mean is that if I don't use any buttons to control the board, the loop breaks.
for(;;) {
if(message.equals("END")) {
break;
}
message = "";
switch (arduinoState) {
case 1: sendMessage("Server[Cmd]: fwd");
arduinoState = 0;
break;
case 2: sendMessage("Server[Cmd]: right");
arduinoState = 0;
break;
case 3: sendMessage("Server[Cmd]: bwd");
arduinoState = 0;
break;
case 4: sendMessage("Server[Cmd]: left");
arduinoState = 0;
break;
case 5: sendMessage("Server[Cmd]: kante");
arduinoState = 0;
break;
}
message = input.readLine();
updateStatusHandler.post(new updateStatusThread("Arduino: " + message, false));
}
EDIT: As requested once, here is the Server class.
So I've found a solution. The problem was that message = input.readLine(); keeps reading lines till the stream ends. As arduinoState = 0, no message will be sent to the client as there's no action to do thus no message from the client will be returned. This ends to a continously loop of reading. This means that even if I would change arduinoState, nothing will happen.
Solution: What I did was creating a class which is treated like a thread. Message will now on be sent independently from the waitForConnection() method.
sendMessageThread are used in setOnClickListeners() for buttons I use in the app.
class sendMessageThread implements Runnable {
private String s = "";
public sendMessageThread(String s) {
this.s = s;
}
public void run() {
try {
mWriter.write(s + '\n');
mWriter.flush();
mHandler.post(new updateStatusThread("Befehl gesendet: \"" + s + "\"", false));
} catch (IOException e) {
e.printStackTrace();
}
}
}
But I had to do a workaround lowering StrictMode. Why? Although I'm using a thread to take network actions, the exception android.os.NetworkOnMainThreadException is thrown. I guess it's because I'm using mWriter (BufferedWriter) as a global reference. I fetch the BufferedWriter in whileConnected() in the Server class.
StrictMode workaround:
//Remember to set it in the onCreate() method,
//right after super.onCreate() and setContentView()
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
whileConnected() method
private void whileConnected() {
try {
mWriter = this.output;
do {
input.ready();
String line;
while((line = input.readLine()) != null) {
if(line.length() > 0) {
mHandler.post(new updateStatusThread("Arduino: " + line, false));
break;
}
}
} while (!message.equals("END"));
} catch (Exception e) {
e.printStackTrace();
}
}
If you still have any questions or tips and tricks to improve myself, feel free to leave an answer or comment down below.
Maybe the issue is infinite looping on UI thread, it's just a guess.
Also, have you tried while loop?

IOIO UART readback problems

I'm extending the BaseIOIOLooper to open up a UART device and send messages. I'm testing with a readback, where I send a packet over a line and receive that packet on another line and print it out. Because I don't want the InputStream.read() method to block, I am handling packet formation and input in a different thread. I have narrowed my problem down to the InputStream.read() method, which returns -1 (no bytes read, but no exception).
Here is what it looks like in the Looper thread:
#Override
protected void setup() throws ConnectionLostException, InterruptedException {
log_.write_log_line(log_header_ + "Beginning IOIO setup.");
// Initialize IOIO UART pins
// Input at pin 1, output at pin 2
try {
inQueue_ = MinMaxPriorityQueue.orderedBy(new ComparePackets())
.maximumSize(QUEUESIZE).create();
outQueue_ = MinMaxPriorityQueue.orderedBy(new ComparePackets())
.maximumSize(QUEUESIZE).create();
ioio_.waitForConnect();
uart_ = ioio_.openUart(1, 2, 38400, Uart.Parity.NONE, Uart.StopBits.ONE);
// Start InputHandler. Takes packets from ELKA on inQueue_
in_= new InputHandler(inQueue_, uart_.getInputStream());
in_.start();
// Start OutputHandler. Takes packets from subprocesses on outQueue_
out_= new OutputHandler(outQueue_);
out_.start();
// Get output stream
os_=uart_.getOutputStream();
// Set default target state
setTargetState(State.TRANSFERRING);
currInPacket_[0]=1; //Initial value to start transferring
log_.write_log_line(log_header_ + "IOIO setup complete.\n\t" +
"Input pin set to 1\n\tOutput pin set to 2\n\tBaud rate set to 38400\n\t" +
"Parity set to even\n\tStop bits set to 1");
} catch (IncompatibilityException e) {
log_.write_log_line(log_header_+e.toString());
} catch (ConnectionLostException e) {
log_.write_log_line(log_header_+e.toString());
} catch (Exception e) {
log_.write_log_line(log_header_+"mystery exception: "+e.toString());
}
}
And in the InputHandler thread:
#Override
public void run() {
boolean notRead;
byte i;
log_.write_log_line(log_header_+"Beginning InputHandler thread");
while (!stop) {
i = 0;
notRead = true;
nextInPacket = new byte[BUFFERSIZE];
readBytes = -1;
//StringBuilder s=new StringBuilder();
//TODO re-implement this with signals
while (i < READATTEMPTS && notRead) {
try {
// Make sure to adjust packet size. Done manually here for speed.
readBytes = is_.read(nextInPacket, 0, BUFFERSIZE);
/* Debugging
for (int j=0;j<nextInPacket.length;j++)
s.append(Byte.toString(nextInPacket[j]));
log_.write_log_line(log_header_+s.toString());
*/
if (readBytes != -1) {
notRead = false;
nextInPacket= new byte[]{1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0};
synchronized (q_) {
q_.add(nextInPacket);
}
//log_.write_log_line(log_header_ + "Incoming packet contains valid data.");
} else i++;
} catch (IOException e) {
log_.write_log_line(log_header_ + "mystery exception:\n\t" + e.toString());
}
}
if (i>=READATTEMPTS)
log_.write_log_line(log_header_+"Too many read attempts from input stream.");
/*
try {
sleep(100);
} catch (InterruptedException e) {
log_.write_log_line(log_header_+"fuck");
}
*/
}
}
On an oscilloscope, pins 1 and 2 both read an oscillating voltage, albeit at a very high amplitude, which is of some concern. Point is nothing is available to be read from the InputStream in the InputHandler class. Any ideas?
-1 returned from read() should only happen whenever the UART is closed. The closure can happen as result of explicitly calling close() on the Uart object or calling softReset() on the IOIO object.
The Android log might give you some clues about what's going on.
The reading you're seeing on the oscilloscope is suspicious: how high is "very high amplitude"? You should only ever see 0V or 3.3V on those pins, or floating in case the pins where not opened (or closed) for some reason.

How to read (all available) data from serial connection when using JSSC?

I'm trying to work with JSSC.
I built my app according to this link:
https://code.google.com/p/java-simple-serial-connector/wiki/jSSC_examples
My event handler looks like:
static class SerialPortReader implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
if(event.isRXCHAR()){//If data is available
try {
byte buffer[] = serialPort.readBytes();
}
catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
}
}
The problem is that I'm always not getting the incoming data in one piece. (I the message has a length of 100 bytes, Im getting 48 and 52 bytes in 2 separates calls)
- The other side send me messages in different lengths.
- In the ICD Im working with, there is a field which tell us the length of the message. (from byte #10 to byte #13)
- I cant read 14 bytes:
(serialPort.readBytes(14);,
parse the message length and read the rest of the message:
(serialPort.readBytes(messageLength-14);
But if I will do it, I will not have the message in once piece (I will have 2 separates byte[] and I need it in one piece (byte[]) without the work of copy function.
Is it possible ?
When working with Ethernet (SocketChannel) we can read data using ByteBuffer. But with JSSC we cant.
Is there a good alternative to JSSC ?
Thanks
You can't rely on any library to give you all the content you need at once because :
the library dont know how many data you need
the library will give you data as it comes and also depending on buffers, hardware, etc
You must develop your own business logic to handle your packets reception. It will of course depend on how your packets are defined : are they always the same length, are they separated with same ending character, etc.
Here is an example that should work with your system (note you should take this as a start, not a full solution, it doesn't include timeout for example) :
static class SerialPortReader implements SerialPortEventListener
{
private int m_nReceptionPosition = 0;
private boolean m_bReceptionActive = false;
private byte[] m_aReceptionBuffer = new byte[2048];
#Override
public void serialEvent(SerialPortEvent p_oEvent)
{
byte[] aReceiveBuffer = new byte[2048];
int nLength = 0;
int nByte = 0;
switch(p_oEvent.getEventType())
{
case SerialPortEvent.RXCHAR:
try
{
aReceiveBuffer = serialPort.readBytes();
for(nByte = 0;nByte < aReceiveBuffer.length;nByte++)
{
//System.out.print(String.format("%02X ",aReceiveBuffer[nByte]));
m_aReceptionBuffer[m_nReceptionPosition] = aReceiveBuffer[nByte];
// Buffer overflow protection
if(m_nReceptionPosition >= 2047)
{
// Reset for next packet
m_bReceptionActive = false;
m_nReceptionPosition = 0;
}
else if(m_bReceptionActive)
{
m_nReceptionPosition++;
// Receive at least the start of the packet including the length
if(m_nReceptionPosition >= 14)
{
nLength = (short)((short)m_aReceptionBuffer[10] & 0x000000FF);
nLength |= ((short)m_aReceptionBuffer[11] << 8) & 0x0000FF00;
nLength |= ((short)m_aReceptionBuffer[12] << 16) & 0x00FF0000;
nLength |= ((short)m_aReceptionBuffer[13] << 24) & 0xFF000000;
//nLength += ..; // Depending if the length in the packet include ALL bytes from the packet or only the content part
if(m_nReceptionPosition >= nLength)
{
// You received at least all the content
// Reset for next packet
m_bReceptionActive = false;
m_nReceptionPosition = 0;
}
}
}
// Start receiving only if this is a Start Of Header
else if(m_aReceptionBuffer[0] == '\0')
{
m_bReceptionActive = true;
m_nReceptionPosition = 1;
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
break;
default:
break;
}
}
}
After writing data to serial port it need to be flushed. Check the timing and pay attention to the fact that read should occur only after other end has written. read size is just an indication to read system call and is not guaranteed. The data may have arrived and is buffered in serial port hardware buffer but may not have been transferred to operating system buffer hence not to application. Consider using scm library, it flushes data after each write http://www.embeddedunveiled.com/
Try this:
Write your data to the serial port (using serialPort.writeBytes()) and if you are expecting a response, use this:
byte[] getData() throws SerialPortException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b;
try {
while ((b = serialPort.readBytes(1, 100)) != null) {
baos.write(b);
// System.out.println ("Wrote: " + b.length + " bytes");
}
// System.out.println("Returning: " + Arrays.toString(baos.toByteArray()));
} catch (SerialPortTimeoutException ex) {
; //don't want to catch it, it just means there is no more data to read
}
return baos.toByteArray();
}
Do what you want with the returned byte array; in my case I just display it for testing.
I found it works just fine if you read one byte at a time, using a 100ms timeout, and when it does time out, you've read all data in the buffer.
Source: trying to talk to an Epson serial printer using jssc and ESC/POS.

Reading and Handling Streams

I want to read and handle a stream of String containing single OR multiple commands in one line.
I am currently using InputStream in = socket.getInputStream(); for my inputstream.
Also for handling the input a typical Thread:
public void run() {
String input = "";
try {
int data = 0;
while (!isInterrupted()) {
while ((data = in.read()) != -1 && !isInterrupted()) {
input += Integer.toHexString(data);
handleInput(input);
}
try {
sleep(500);
} catch (InterruptedException e) {
break;
}
}
socket.close();
return;
} catch (IOException e) {
main.log("Connection lost...");
main.log(e.toString());
main.stopBTCommunication();
main.startBTServer();
}
}
handleInput() is designed to handle any String given to it and response correctly. The problem with this implementation would be, that handleInput() is called with every byte read from in.read(). I know, that i could use BufferedReader.readLine(), but that would require every incomming command to have "\n" appended to it, which is NOT the case and can't be changed.
I know that
while (!isInterrupted()) {
while ((data = in.read()) != -1 && !isInterrupted()) {
is kind of nuisance, but basically it want the Thread to read until nothing new is read, then handle that input and then read again...
EDIT:
So basically, what i need is a non-blocking read().
EDIT2:
How can incoming commands and commandchains look like:
Select Command: "s"
ReadLine Command: "rlXX" whereby X is a Hex Digit
WriteLine Command: "wlXXSSSSSSSS" whereby X and S are Hex Digits
So a commandschain may look like one of the following:
"s"
"srlff" = "s" + "rlff"
"rlffwlbb2e2e2e2erlbb" = "s" + "rlff" + "wlbb2e2e2e2e" + "rlbb"
I don't think you really need a non-blocking read. You need a method that reads the stream byte by byte and translates it into commands as it goes.
Something like:
public void processStream(InputStream in) {
List<Command> commands = new ArrayList<Command>();
while((int c = in.getChar()) != -1 ) {
switch((char)c) {
case 's':
commands.add(new SelectCommand());
break;
case 'r':
commands.add(ReadCommand.buildFromStream(in));
break;
case 'w':
commands.add(WriteCommand.buildFromStream(in));
break;
case ';':
commandEngine.execute(commands);
break;
default:
throw new StreamParseError("unexpected character: " + c);
}
}
}
This assumes that SelectCommand, ReadCommand, WriteCommand are type-compatible with Command.
... with for example ReadCommand.buildFromStream being:
public static ReadCommand buildFromStream(InputStream in) {
if((char)in.read() != 'n') {
throw new StreamParseError("Expect 'l' after 'r'");
}
// bad error checking here - be less lazy in real life.
String hexNum = in.read() + in.read();
int num = Integer.parseInt(hexNum,16);
return new ReadCommand(num);
}
This is very primitive parsing, but it shows the principle. There are well established techniques for more advanced parsing, which you can read up on if you want to.
You could also use a Scanner. Most commonly, Scanner is used with delimiters, but it can also look for regex patterns.
Scanner scanner = new Scanner(stream);
String cmd = "";
while(cmd != "e") { // I made up an "end" command :)
cmd = scanner.findWithinHorizon("(s|rl..|wl.{8}|e)",12);
if(cmd == null) {
// end of input, or badly formed input
break;
}
handleCmd(cmd);
}
You can read in array of bytes like this
int bytesRead = 0;
byte[] buffer = new byte[1024]; // reads up to 1024 byte chunks
while((bytesRead = in.read(buffer)) != -1) {
for ( int i = 0; i < bytesRead; i++ ) {
input += Integer.toHexString(buffer[i]);
}
handleInput(input);
}
The above code calls is the same as your old code that "input" keeps growing and used over and over again to call handleInput(). No sure if this is your intention but it looks suspicious.
Note that you are reading data from a stream. This means that you will have to implement recovery of the commands' structure yourself, i.e. you must at least detect the beginning and end of a command in your own code.
This again leads to another problem: You have no guarantee about how your stream's data is split into "chunks" by the transport layer. You may receive one command plus half a command in one read(buffer) call and then the second half of the command plus some more data in the next read(buffer).
Therefore, what I recommend is that you keep reading data only until you detect the end of one message/command/whatever and then perform handling for only this single message, before reading more incoming data and repeating. Everything else (i.e. dealing with partially received messages) easily becomes messy.
EDIT - With this particular input/output, since you don't have a delimiter, Scanner may not be the way to go here, but if you've got a delimiter between commands, it would be a great option, so I'll keep the answer here in the hopes it might help someone in the future.
Since your example doesn't have a delimiter, I have to get a little bit hack-y to demonstrate scanner's awesomeness, but it should still work for the exact commands you've listed. It would not be a good choice if you expect the command vocabulary to change.
I'd really recommend the use of delimiters if at all possible. It makes life much easier.
I'd look at the Scanner class if I were you.
The Scanner can wrap your input stream, and then scan based on a regex or delimter to grab chunks of input. Then your handleInput() method can operate on chunks (whole commands) rather than individual bytes.
Here's a brief, standalone example:
package com.stackoverflow.q22199860;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.regex.Pattern;
public class ReadStream
{
public static void main(String[] args)
{
Pattern commandPattern = Pattern.compile("s|rl|wl");
String commands = "srlffwlbb2e2e2e2erlbb";
Charset utf8 = StandardCharsets.UTF_8;
try (
InputStream inputStream = new ByteArrayInputStream(commands.getBytes(utf8));
Scanner scanner = new Scanner(inputStream, utf8.name());
) {
scanner.useDelimiter(commandPattern);
while(scanner.hasNext()) {
String command = scanner.next();
if (command.isEmpty()){
//s
System.out.println("s" + command);
} else if (command.length() == 2) {
//rl
System.out.println("rl" + command);
} else if (command.length() == 10) {
//wl
System.out.println("wl" + command);
}
}
}
catch (IOException e)
{
System.err.println("Error Reading Stream");
}
}
}
The output from this is:
s
rlff
wlbb2e2e2e2e
rlbb

socket communication in java

this.cin = new DataInputStream(this.csocket.getInputStream());
public class ReceiveMessage extends Thread{
public void run(){
while(stop == false)
try {
if(cin.available()>0)
receMessage();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// choke, unchoke, interested, notinterested, have, bitfield, request, piece
public void receMessage(){
int rv=0;
byte[] length = new byte[4]; // total length
try {
rv = cin.read(length, 0, 4);
} catch (IOException e) {
e.printStackTrace();
}
if(rv <=0)
return;
byte[] type = new byte[1];
try {
cin.read(type, 0, 1);
} catch (IOException e) {
e.printStackTrace();
}
int size = byte2int(length) -4 -1; //size of payload
clearPayload();
if(size > 0){
try {
cin.read(this.payload, 0, size);
} catch (IOException e) {
e.printStackTrace();
}
}
byte mtype = type[0];
switch(mtype){
case (byte)0:
receNoPayload((byte)0);
break;
case 1:
receNoPayload((byte)1);
break;
case 2:
receNoPayload((byte)2);
break;
case 3:
receNoPayload((byte)3);
break;
case 4:
receHave(payload);
break;
case 5:
receBitField(payload);
break;
case 6:
receRequest(payload);
break;
case 7:
recePiece(payload, size);
break;
default:
System.out.println("wrong message type!");
}
}
the code above is used to read data from socket. I create a thread to read data from socket.and then analyze the data according the type of message contained in data.
Now, the problem is if I transfer 100 bytes into socket, I can do everything correctly; however, if I transfer 1000 bytes into socket, sometimes, the data read out is wrong. for example, the variable type cannot be greater than 7 normally. But now the type read out is greater than 7, which is wrong.
in both case, I do not change anything, except the size of data transferred.
please help me, thank you! I have done everything I can do, but i still cannot figure it out.
Get rid of the available() call. The read() will block if there is no data. At present you're just burning the CPU.
Check the result of each read. You can't assume it filled the buffer. Or use DataInputStream.readFully() instead.

Categories