2013-11-17 8 views
1

Мне нужно написать некоторый байт для последовательного соединения. Однако я не могу найти что-то в библиотеке JSSC, чтобы установить тайм-аут записи. Мне нужен этот таймаут, потому что если я настрою аппаратное управление потоком, и я удалю кабель, мое приложение застряло, ожидая сигнала CTS.Установка последовательного соединения JSSC Время ожидания записи

UPDATE

Я попробовал этот обходной путь с объектом будущего:

ExecutorService executor = Executors.newSingleThreadExecutor(); 
    ... 
    public synchronized void write(byte[] content, int timeout) throws InterruptedException, SerialPortException{ 
      long starttime = System.currentTimeMillis(); 
      Future<Boolean> future = executor.submit(new Callable<Boolean>() { 
       public Boolean call() throws Exception { 
        serialPort.writeBytes(content); 
        return new Boolean(true); 
       } 
      }); 
      try { 
       future.get(timeout, TimeUnit.MILLISECONDS); 
       log.debug("Duration: {}",DurationFormatUtils.formatDuration(System.currentTimeMillis() - starttime, "mm:ss.SS")); 
      } catch (ExecutionException e) { 
       throw new HardwareException(e.getMessage()); 
      } catch (TimeoutException e) { 
       throw new HardwareException("Impossibile scrivere nella porta seriale (timeout)"); 
      } 
     } 

Но это не очень хорошо работает, оно принимает 4s писать 550byte через COM-порт 256000 бод ...

Попытка прямой записи:

public synchronized void write(byte[] content, int timeout) throws InterruptedException, SerialPortException{ 
     try { 
      long starttime = System.currentTimeMillis(); 
      serialPort.writeBytes(content); 
      log.debug("Duration: {}",DurationFormatUtils.formatDuration(System.currentTimeMillis() - starttime, "mm:ss.SS")); 
     } catch (SerialPortException e) { 
      throw new HardwareException(e.getMessage()); 
     } 
    } 

Потребовалось 0.5s, как ожидалось!

Проблема заключается в том, что ключевое слово «syncronized» в основном методе, почему?

+0

Является ли это JSSC? http://code.google.com/p/java-simple-serial-connector/ – dsolimano

+0

Да, это ... – Tobia

ответ

1

У меня была та же проблема. Я решил это, запустив два потока: один, чтобы написать один, чтобы подождать определенное количество времени. В зависимости от первого, который заканчивается, запись является успешной или таймаутом. Вот различные классы, которые я использовал:

ByteWriter: интерфейс для общего байта письма (я хотел, чтобы иметь возможность переключаться с АСК в какой-либо другой структуры

package net.femtoparsec.jssc; 

import java.io.IOException; 

public interface ByteWriter { 

    void write(byte[] bytes) throws IOException; 

    void write(byte oneByte) throws IOException; 

    void write(byte[] bytes, long timeout) throws IOException, InterruptedException; 

    void write(byte oneByte, long timeout) throws IOException, InterruptedException; 

    void cancelWrite() throws IOException; 

} 

JsscByteWriter: реализация ByteWriter для JSSC

package net.femtoparsec.jssc; 

import jssc.SerialPort; 
import jssc.SerialPortException; 

import java.io.IOException; 

public class JsscByteWriter implements ByteWriter { 

    private final SerialPort serialPort; 

    public JsscByteWriter(SerialPort serialPort) { 
     this.serialPort = serialPort; 
    } 

    @Override 
    public void cancelWrite() throws IOException { 
     try { 
      serialPort.purgePort(SerialPort.PURGE_TXABORT); 
      serialPort.purgePort(SerialPort.PURGE_TXCLEAR); 
     } catch (SerialPortException e) { 
      throw new IOException(e); 
     } 
    } 

    @Override 
    public void write(byte[] bytes) throws IOException { 
     try { 
      serialPort.writeBytes(bytes); 
     } catch (SerialPortException e) { 
      throw new IOException(e); 
     } 
    } 

    @Override 
    public void write(byte oneByte) throws IOException { 
     try { 
      serialPort.writeByte(oneByte); 
     } catch (SerialPortException e) { 
      throw new IOException(e); 
     } 
    } 

    @Override 
    public void write(byte[] bytes, long timeout) throws IOException, InterruptedException { 
     if (timeout <= 0) { 
      this.write(bytes); 
     } 
     else { 
      new TimedOutByteWriting(this, bytes, timeout).write(); 
     } 
    } 

    @Override 
    public void write(byte oneByte, long timeout) throws IOException, InterruptedException { 
     if (timeout <= 0) { 
      this.write(oneByte); 
     } 
     else { 
      new TimedOutByteWriting(this, oneByte, timeout).write(); 
     } 
    } 


} 

TimedOutByteWriting: класс для выполнения таймаут письма

package net.femtoparsec.jssc; 

import java.io.IOException; 
import java.util.Objects; 
import java.util.concurrent.*; 
import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

class TimedOutByteWriting { 

    private final ByteWriter byteWriter; 

    private final boolean onlyOneByte; 

    private final byte oneByte; 

    private final byte[] bytes; 

    private final long timeout; 

    private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool(r -> { 
     Thread t = new Thread(r, "TimedOutByteWriting Thread"); 
     t.setDaemon(true); 
     return t; 
    }); 

    TimedOutByteWriting(ByteWriter byteWriter, byte oneByte, long timeout) { 
     if (timeout <= 0) { 
      throw new IllegalArgumentException("Invalid time out value : "+timeout+". Must be greater than 0"); 
     } 
     this.byteWriter = Objects.requireNonNull(byteWriter, "byteWriter"); 
     this.bytes = null; 
     this.oneByte = oneByte; 
     this.timeout = timeout; 
     this.onlyOneByte = true; 
    } 

    TimedOutByteWriting(ByteWriter byteWriter, byte[] bytes, long timeout) { 
     if (timeout <= 0) { 
      throw new IllegalArgumentException("Invalid time out value : "+timeout+". Must be greater than 0"); 
     } 
     this.byteWriter = Objects.requireNonNull(byteWriter, "byteWriter"); 
     this.bytes = Objects.requireNonNull(bytes, "bytes"); 
     this.timeout = timeout; 
     this.oneByte = 0; 
     this.onlyOneByte = false; 
    } 

    void write() throws IOException, InterruptedException { 
     final Lock lock = new ReentrantLock(); 
     final Condition condition = lock.newCondition(); 
     final Result result = new Result(); 

     final Future<?> writeThread = EXECUTOR_SERVICE.submit(new WriteRunnable(result, lock, condition)); 
     final Future<?> timeoutThread = EXECUTOR_SERVICE.submit(new TimeoutRunnable(result, lock, condition)); 

     lock.lock(); 
     try { 
      if (!result.timedout && !result.writeDone) { 
       try { 
        condition.await(); 
       } catch (InterruptedException e) { 
        writeThread.cancel(true); 
        timeoutThread.cancel(true); 
        throw e; 
       } 
      } 
      if (!result.writeDone) { 
       byteWriter.cancelWrite(); 
      } 
      else { 
       timeoutThread.cancel(true); 
      } 
     } 
     finally { 
      lock.unlock(); 
     } 

     result.handleResult(); 
    } 

    private abstract class TimedOutByteWritingRunnable implements Runnable { 

     protected final Result result; 

     final Lock lock; 

     final Condition condition; 

     TimedOutByteWritingRunnable(Result result, Lock lock, Condition condition) { 
      this.result = result; 
      this.lock = lock; 
      this.condition = condition; 
     } 
    } 

    private class WriteRunnable extends TimedOutByteWritingRunnable { 

     private WriteRunnable(Result result, Lock lock, Condition condition) { 
      super(result, lock, condition); 
     } 

     @Override 
     public void run() { 
      IOException exception; 
      try { 
       if (onlyOneByte) { 
        byteWriter.write(oneByte); 
       } else { 
        byteWriter.write(bytes); 
       } 
       exception = null; 
      } catch (IOException e) { 
       exception = e; 
      } 
      lock.lock(); 
      try { 
       result.writeException = exception; 
       result.writeDone = exception == null; 
       condition.signalAll(); 
      } finally { 
       lock.unlock(); 
      } 
     } 
    } 

    private class TimeoutRunnable extends TimedOutByteWritingRunnable { 

     private TimeoutRunnable(Result result, Lock lock, Condition condition) { 
      super(result, lock, condition); 
     } 

     @Override 
     public void run() { 
      boolean interrupted; 
      try { 
       TimeUnit.MILLISECONDS.sleep(timeout); 
       interrupted = false; 
      } catch (InterruptedException e) { 
       interrupted = true; 
      } 

      lock.lock(); 
      try { 
       result.timedout = !interrupted; 
       condition.signalAll(); 
      } finally { 
       lock.unlock(); 
      } 
     } 
    } 


    private static class Result { 

     IOException writeException; 

     boolean writeDone = false; 

     boolean timedout = false; 

     void handleResult() throws IOException { 
      if (writeDone) { 
       return; 
      } 
      if (timedout) { 
       throw new TimeoutException("Write timed out"); 
      } 
      else if (writeException != null) { 
       throw writeException; 
      } 
     } 
    } 

} 
.

И TimeoutException

package net.femtoparsec.jssc; 

import java.io.IOException; 

public class TimeoutException extends IOException { 

    public TimeoutException(String message) { 
     super(message); 
    } 
} 

Тогда просто создать JsscByteWriter и использовать методы, с помощью параметра тайм-аута для записи с тайм-аут.

0

При использовании управления потоком запись будет блокироваться, если достигнут порог, чтобы предотвратить переполнение буфера. Например, если символ XOFF был принят, драйвер или ОС не разрешат последовательный порт отправлять данные на удаленный конец. Вышеупомянутый подход, такой как отмена потока, может оставить операцию последовательного порта в несогласованном состоянии, если используется перекрытие IO (windows). Мы манипулируем вещами в слое java, но что касается собственного слоя. Пожалуйста, поправьте меня, если я что-то пропустил.

Рассмотрите возможность использования другой библиотеки последовательных портов, например SCM, или измените собственный код jssc для обработки таких ситуаций.

+0

SCM обрабатывает эти случаи? – Tobia

+0

Да, он обрабатывает все элементы управления потоком и выше. – samuel05051980