Как избежать тайм-аута в QSerialPort при обработке высокоскоростных данных

Я работаю над приложением Windows, которое получает данные от датчика на частоте 600 Гц. В двух из пяти случаев мой поток ввода-вывода успешно считывает 4 байта данных с датчика и передает их в поток графического интерфейса.

Проблема в трех из пяти раз, QSerialPort имеет необъяснимые тайм-ауты, где waitForReadyRead () QSerialPort возвращает false, а serial.errorString () имеет ошибку тайм-аута. В этом случае он никогда не будет читать данные. Если я читаю с последовательного порта, несмотря на ошибку тайм-аута, я буду читать 2000+ байтов данных в следующем waitForReadyRead, который будет доставлен кусками, что делает аспект приема данных в реальном времени моего приложения устаревшим.

Я попытался использовать сигнал readyRead () последовательного порта, но он демонстрирует то же поведение, т.е. если появляется ошибка тайм-аута, сигнал readyRead () никогда не срабатывает.

ОБНОВИТЬ: Я могу воспроизвести проблему с примером терминала Qt ([QT_INSTALL_EXAMPLES] / serialport / терминал), который использует неблокирующее чтение. Частота появления ошибки значительно меньше, но она определенно есть.

ОБНОВИТЬ: Используя Serial Port Monitor, я вижу, что когда он застревает, пример терминала Qt застревает на IOCTL_SERIAL_WAIT_ON_MASK, мой пример застревает на IRP_MJ_WRITE DOWN сразу после IOCT_SERIAL_WAIT_ON_MASK. Этого никогда не происходит с другими терминальными программами, что наводит меня на мысль, что проблема определенно в Qt.

Pastebin выхода монитора последовательного порта

void IOThread::run(){

QSerialPort serial;
serial.setPortName(portname)
serial.setBaudRage(QSerialPort::Baud115200);
serial.setStopBits(QSerialPort::OneStop)
serial.setParity(QSerialPort::NoParity);
serial.setDataBits(QSerialPort::Data8);
serial.setFlowControl(QSerialPort::NoFlowControl);

if(!serial.open(QIODevice::ReadWrite)
{
qDebug() << "Error Opening Port";
return;
}
else
{
qDebug() << "Error Message: " << serial.errorString() // prints "Unknown Error"}

while(true)
{
if(serial.waitForReadyRead(1000))
{
qDebug() << "Normal read";
reception_buffer = serial.readAll();
}
else
{
qDebug() << "Timeout";
/* serial.readAll() here will read nothing but force next read to read huge chunk of data */
continue;
}
}

// Process data...
}

1

Решение

Попробуйте, если это имеет какое-либо значение:

while (true) {
QByteArray reception_buffer;
if (serial.waitForReadyRead(1000)) {
reception_buffer = serial.readAll();
while (serial.waitForReadyRead(10)) {
reception_buffer += serial.readAll();
}
qDebug() << "reception_buffer ready";
}
else {
qDebug() << "Timeout";
}
}

Если вы хотите предотвратить таймаут от waitForReadyRead Вы можете установить:

if(serial.waitForReadyRead(-1))

bool QSerialPort :: waitForReadyRead (int msecs = 30000) время ожидания истечет через миллисекунды; время ожидания по умолчанию составляет 30000 миллисекунд. Если msecs равен -1, функция не будет иметь тайм-аут.

0

Другие решения

застревает на IOCTL_SERIAL_WAIT_ON_MASK

Скорее всего, проблема в вашем HW или драйвере. QSP использует асинхронное уведомление, основанное на WaitCommEvent. Если WaitCommEvent застревает — проблема в вашем устройстве или драйвере (скорее всего).

0

Спасибо ребятам из QSerialPort, эта ошибка в Qt 5.10.1 решается путем применения этого патча: https://codereview.qt-project.org/#/c/225277/

«QSP может игнорировать все события чтения, когда данные поступают на устройство
в открытии. В этом случае даже повторное открытие устройства не
Помогите. Причина в том, что QWinOverlappedIoNotifier включен после
чем вызывается startAsyncCommunication (), что, вероятно, приводит к
игнорирование для всех событий EV_RXCHAR. Обходной путь должен включить
уведомитель раньше, чем какая-либо из операций ввода / вывода. «- Денис Шиенков, QSerialPort Maintainer

0
По вопросам рекламы [email protected]