2

I have a serial device connected to my PI that I read data from it... everything is good , but sometime the cable move or the serial device is unplug.

then the

line = r.readLine();

get stuck

I have try to overcome this problem by:

BufferedReader r = new BufferedReader (newnputStreamReader(p.getInputStream()));     
         try 
            {
                line = r.readLine();
                if (line.length() == 0)
                {
                    logfile.append("problem");
                    logfile.close();
                    System.out.println("Problem");
                    TimeUnit.SECONDS.sleep(5);
                    break;
                }

            }
            catch (IOException e)
            {
                logfile.append(line);
                logfile.close();
            }

but it doens't do nothing (because I geuss he is still waiting for data) not even throw an exception how can I make him say I have a problem ? maybe to use a timer or something like this ? if no data for 5 seconds ?

Thanks ,

Korenron
  • 101
  • 9

2 Answers2

0

Your assumption in this case is right. The readLine() method of the BufferedReader has an internal while-loop which will retrieve all bytes from the underlying input stream and will only break if the arriving character is either \n or \r.

Think of it like:

while(lastChar != '\n' || lastChar != '\r')
{
     //read from stream
}

However once entered the method will not return. The only exceptions are the occurence of those two special characters or if the InputStream is closed (in which case null ist returned).

The trick is to no enter until there is something to read from the InputStream:

public static void main( String[] args ) throws IOException
{

  boolean awaitInput = true;

  while(awaitInput)
  {
    if(System.in.available() != 0)
    {
      awaitInput = false;
      // read logic
    }
  }
}

This is only one of many possible solutions and I used System.in as an example since it is a InputStream like any other as well. But there is also a method called BufferedReader#ready which returns true if there is something to read:

public static void main( String[] args ) throws IOException
{

  BufferedReader br = new BufferedReader( new InputStreamReader(System.in) );

  boolean awaitInput = true;

  while(awaitInput)
  {
    if(br.ready())
    {
      awaitInput = false;
      String line = br.readLine();
      // read logic
    }
  }
}

At last if you want a timeout you can easily do it yourself like this:

public static void main( String[] args ) throws IOException
{
  BufferedReader br = new BufferedReader( new InputStreamReader(System.in) );
  boolean awaitInput = true;
  long timeout = System.currentTimeMillis() + 5_000;
  //                                          ^^^^^ 5_000ms = 5 sec 

  while(awaitInput && System.currentTimeMillis() < timeout)
  {
    if(br.ready())
    {
      awaitInput = false;
      String line = br.readLine();
      // read logic
    }
  }
}
L.Spillner
  • 1,552
  • 7
  • 17
  • great I have done what you expalin using the System.in.available - and now I think it's OK . I will continue work on it and see if I have more problem... Thanks – Korenron Jun 11 '18 at 14:38
  • I have try for 1 day to run the r.ready() ,2nd option . and it's gibe me fault once every ~ 3 seconds. while whn I read the data with simple serial program (putty) - I don't get any disconnection.... so it's strange , maybe I can give the read "more" time to read? – Korenron Jun 12 '18 at 11:04
0

You can use CompletableFuture to read concurrently and be able to use a timeout.

// wrap the readLine into a concurrent call
CompletableFuture<String> lineFuture = CompletableFuture.supplyAsync(() -> r.readLine());
try {
    // do the call, but with a timeout
    String readLine = lineFuture.get(5, TimeUnit.SECONDS);
    // do stuff with the line you read
} catch (TimeoutException e) {
    // plug pulled?
}
daniu
  • 12,131
  • 3
  • 23
  • 46