Проблемы с получением в RXTX
Я использую RXTX около года без особых проблем. Я только запустил новую программу для взаимодействия с новым оборудованием, поэтому я повторно использовал метод connect(), который я использовал в других своих проектах, но у меня есть странная проблема, которую я никогда раньше не видел.
Эта проблема
Устройство работает нормально, потому что когда я подключаюсь к HyperTerminal, я отправляю и получаю то, что ожидаю, и Serial Port Monitor(SPM) отражает это.
Однако, когда я запускаю простой HyperTerminal-клон, который я написал, чтобы диагностировать проблему, с которой я сталкиваюсь с моим основным приложением, байты отправляются, согласно SPM, но ничего не получается, и мой SerialPortEventListener никогда не срабатывает. Даже когда я проверяю доступные данные в основном цикле, reader.ready()
возвращается false
, Если я проигнорирую эту проверку, то получу исключение, подробности ниже.
Соответствующий раздел метода connect()
// Configure and open port
port = (SerialPort) CommPortIdentifier.getPortIdentifier(name)
.open(owner,1000)
port.setSerialPortParams(baud, databits, stopbits, parity);
port.setFlowControlMode(fc_mode);
final BufferedReader br = new BufferedReader(
new InputStreamReader(
port.getInputStream(),
"US-ASCII"));
// Add listener to print received characters to screen
port.addEventListener(new SerialPortEventListener(){
public void serialEvent(SerialPortEvent ev) {
try {
System.out.println("Received: "+br.readLine());
} catch (IOException e) { e.printStackTrace(); }
}
});
port.notifyOnDataAvailable();
исключение
java.io.IOException: Underlying input stream returned zero bytes
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:268)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.read(BufferedReader.java:157)
at <my code>
Большой вопрос (снова)
Я думаю, что я устранил все возможные аппаратные проблемы, так что может быть не так с моим кодом или библиотекой RXTX?
Редактировать: что-то интересное
Когда я открываю HyperTerminal после отправки набора команд из Java, которые должны были получить ответы, все ответы появляются немедленно, как если бы они были помещены в буфер где-то, но недоступны.
Редактировать 2: пробовал что-то новое, те же результаты
Я запустил пример кода, найденный здесь, с теми же результатами. Данные не поступали, но когда я переключился на новую программу, она пришла сразу.
Редактировать 3
Аппаратное обеспечение в порядке, и даже другой компьютер имеет ту же проблему. Я не использую какой-либо USB-адаптер.
Я тоже начал использовать PortMon, и это дает мне интересные результаты. HyperTerminal и RXTX не используют одинаковые настройки, а RXTX всегда опрашивает порт, в отличие от HyperTerminal, но я до сих пор не вижу, какие настройки повлияют на это. Как только я смогу изолировать конфигурацию от постоянного опроса, я опубликую свои логи PortMon.
Редактировать 4
Возможно ли, что какое-то обновление Windows за последние 3 месяца могло вызвать это? Однажды он испортил одну из моих программ на основе MATLAB mex.
Редактировать 5
Я также заметил некоторые отличия между HyperTerminal, RXTX и отдельной программой, которая, как я обнаружил, связывается с устройством (но не делает то, что я хочу, поэтому я запускаю свою собственную программу)
- HyperTerminal - отключено управление потоком, но индикаторы RTS и DTR монитора последовательного порта горят зеленым
- Другая программа - не уверен, какие настройки он использует, но только индикатор RTS SPM горит зеленым
- RXTX - независимо от того, какое управление потоком я установил, включены только индикаторы CTS и DTR в SPM.
Из файлов справки монитора последовательного порта (перефразировано):
the indicators display the state of the serial control lines
RTS - Request To Send
CTS - Clear To Send
DTR - Data Terminal Ready
6 ответов
Хорошо, извини, что я так долго возвращался к этому вопросу. Вот как у меня все работает.
Примечание: этот метод не будет работать для всех, пожалуйста, прочитайте ниже, прежде чем копировать / вставлять в свой собственный код
public void connect(CommPortIdentifier portId) throws Failure {
if (portId == null)
throw new Failure("No port set");
try { port = (SerialPort) portId.open(getClass().getName(), 10000); }
catch (PortInUseException e) {
throw new Failure("Port in use by " + e.currentOwner,e); }
try {
port.setSerialPortParams(9600, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
port.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN
| SerialPort.FLOWCONTROL_RTSCTS_OUT);
} catch (UnsupportedCommOperationException e) { throw new Failure(e); }
port.setRTS(true);
// More setup
}
Итак, в моем случае проблема заключалась в том, что мое конкретное устройство требует управления потоком данных RTS. Другие устройства могут требовать разные вещи (CTS, XON/XOFF), поэтому проверьте руководство этого устройства. По умолчанию RXTX отключает все механизмы управления потоком (в отличие от Hypertrm или других программ). Включение каждого из них - двухэтапный процесс.
- Если у вас есть объект SerialPort, вызовите
setFlowControlMode()
метод и побитовое ИЛИ ('|
') необходимостьSerialPort.FLOWCONTROL_
константы - Установите соответствующий контроль потока на true или false (как я сделал с
port.setRTS(true)
)
Для других с подобными проблемами, если это не работает, я предлагаю
- Используя программу мониторинга последовательного порта, такую как Serial Port Monitor и / или PortMon (обе Windows), чтобы увидеть, что на самом деле происходит.
- По электронной почте разработчикам RXTX по адресу rxtx@qbang.org (они очень полезны)
Существует более простое решение этой проблемы. Вот что я сделал:
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while (keepRunning) {
try {
while ((br.ready()) && (line = br.readLine()) != null) {
....
}
Если вы проверяете, что буфер "готов", прежде чем читать его, проблем не должно быть.
Хорошо, я понимаю, что эта тема очень старая, но ни одно из этих решений не помогло мне. У меня была такая же проблема, и я пытался все исправить, но безрезультатно. Затем я провел некоторое исследование того, что вызывает проблему, и, когда не имеет дело с последовательной связью, это происходит в конце файла. Итак, я решил, что мне нужно добавить окончание к тому, что получает Java-приложение, в частности, строку возврата (\n). И, конечно же, это решило проблему для меня! Надеюсь, это поможет кому-то новому, так как я не ожидаю, что это поможет кому-то уже в этой теме...
Я попробовал RXTX несколько месяцев назад и столкнулся с подобными проблемами. Я предлагаю две вещи:
Создайте виртуальный компорт, используя com0com. Включите ведение журнала трассировки. Сравните журналы, когда вы используете Hyperterminal и когда вы запускаете свою собственную программу. Разница в том, что вы делаете неправильно.
По моему скромному мнению, дизайн RXTX несовершенен, а его реализация довольно глючная (посмотрите на его исходный код, какой беспорядок!). Я опубликовал альтернативную библиотеку по адресу http://kenai.com/projects/jperipheral со следующими предостережениями: она предназначена только для Windows и в ней нет встроенных двоичных файлов. Оба они изменятся в ближайшем будущем. Если вы хотите попробовать его, отправьте мне письмо по http://desktopbeautifier.com/Main/contactus и я вышлю вам предварительно собранную версию.
Если кто-то все еще получает java.io.IOException: Underlying input stream returned zero bytes
после того, как вы прочитали свои символы, используя br.readline() для RXTX (даже когда вы сначала проверяете, является ли br.readline() == null), просто сделайте это простое исправление с помощью try/catch:
String line;
while (true){
try{
line = br.readLine();
}catch(IOException e){
System.out.println("No more characters received");
break;
}
//Print the line read
if (line.length() != 0)
System.out.println(line);
}
Я провел некоторые поиски, и кажется, что это лучший / самый простой способ обойти эту проблему.
РЕДАКТИРОВАТЬ: Я беру это обратно. Я попробовал это и все еще заканчивал тем, что имел некоторые проблемы. Я бы порекомендовал работать непосредственно с необработанным InputStream и реализовывать собственный метод read / readLine с помощью InputStream.read(). Это сработало для меня.
(может быть слишком простым, но может с чего-то начать...)
Порт используется? Скорее, чем:
port = (SerialPort) CommPortIdentifier.getPortIdentifier(name)
.open(owner,1000)
как насчет:
CommPortIdentifier portIdentifier;
try {
portIdentifier = CommPortIdentifier.getPortIdentifier(name);
} catch (NoSuchPortException nspe) {
// handle?
}
if (portIdentifier.isCurrentlyOwned()) {
// handle?
}
port = portIdentifier.open(owner, 1000);
if (!(port instanceof SerialPort)) {
// handle?
}
Вы глотаете какие-либо исключения?