Russian Qt Forum

Qt => Вопросы новичков => Тема начата: paibolit от Ноябрь 06, 2020, 19:32



Название: QSerial приём данных
Отправлено: paibolit от Ноябрь 06, 2020, 19:32
Если не затруднит когото кто досконально знает работу QSerial объясните пожалуйста как правильно принимать данные. Пересмотрел, перегуглил, перепробовал разные варианты, но так и не понял как это правильно делать :o. Можно ли принимать данные не используя сигнала
Код:
readyRead()
- у меня не получилось. :-\. Сигнал
Код:
readyRead()
у меня испускается только после выполнения
Код:
serial->waitForReadyRead(100);
Число принимаемых данных небольшое 10-50 байт. Данные принимаются после отправки запроса (с этим проблем нет). Самое неприятное (что собственно и подвигло к написанию данного поста) это возникновение ошибки "TimeoutError" после выполнения команды waitForReadyRead. Значение задержки на появление ошибки не влияет. Данные принимаются полностью и с ошибкой "TimeoutError" следующим кодом:
Код:
    connect(serial, SIGNAL(readyRead()), this, SLOT(read()));
.
//Подготовка запроса для COM порта
.
.
    lenRead=.....//Расчёт длины пакета от микроконтроллера
    serial->write(m_arrCom);// Запись запроса в последовательный порт
    this->thread()->msleep(100);// Засыпаем, ожидая, пока микроконтроллер обработает данные и ответит.
  m_arrCom.clear();//Очищаем буфер перед приёмом данных
  serial->waitForReadyRead(300);
      if (m_arrCom.size()!=lenRead)
          outLog("Ответ не подходит по длине Bytes read: "+QString::number(m_arrCom.size())
                  +" tim:"+QString::number(tim_read.elapsed())+" lenRead:"+QString::number(lenRead));

void SendCom::read()
{
        m_arrCom += serial->readAll();
}


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 06, 2020, 20:06
Не на семёрке такое, случайно?


Название: Re: QSerial приём данных
Отправлено: paibolit от Ноябрь 06, 2020, 20:52
Не на семёрке такое, случайно?
Так точно - на семёрке)). Есть ещё комп с 10й и с QT, могу попробовать и там.


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 06, 2020, 22:12
Так точно - на семёрке)). Есть ещё комп с 10й и с QT, могу попробовать и там.
Просто вопрос такой на этом форуме уже был. Более того, некоторое время назад я уже наступал на эти грабли. Позже даже описание этого бага встречал на забугорных багзиллах.
На тот момент, я смог решить этот вопрос только создав отдельный процесс, который просто считывал данные в цикле, вообще не используя тот сигнал. 10-ка вполне работала. Как и linux, конечно.
Сразу скажу: ещё и тут я спорить не буду. Возможно, что эта ошибка проявляется не у всех. У меня проявилась. И я её решил. Вот таким костылём.


Название: Re: QSerial приём данных
Отправлено: paibolit от Ноябрь 06, 2020, 22:34
Считывал данные не юзая сигнал readyRead()?
Или вообще не юзая QSerialport?

Перенёс проект на Win10 - поведение точь точь как и на семёрке....... Версия QT везде 5.15. Как то странно чтобы такие "детские" баги до сих пор имели место..........
Может ктото из гуру всё таки подскажет куда копать ?


Название: Re: QSerial приём данных
Отправлено: sergek от Ноябрь 06, 2020, 23:18
1) сделайте для передачи данных в порт отдельный буфер;
Код
C++ (Qt)
serial->write(request);
 
2) вот это не нужно, удалите:
Код
C++ (Qt)
this->thread()->msleep(100);
m_arrCom.clear();
serial->waitForReadyRead(300);
Не надо спать. Когда ответит, получите данные в слоте. А тот ответ, что пришел, когда вы спали - вы благополучно удалили...
3) это перенесите в слот read
Код
C++ (Qt)
if (m_arrCom.size()!=lenRead)
  outLog("....");
 
например:
Код
C++ (Qt)
void SendCom::read()
{
   m_arrCom += serial->readAll();
   if (m_arrCom.size()!=lenRead) {
       outLog("....");
       return;
   }
   ...
}
 


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 07, 2020, 12:53
Считывал данные не юзая сигнал readyRead()?
Да. Только чистый QSerialPort.
Вариант читать в отдельном потоке, это костыль. Но - вполне работающий.

Этот баг бережно переносят из версии в версию, иногда починяя. :)
Я лично виндой не пользуюсь, поэтому замечаю только тогда, когда клиенту нужен асинхронный порт. И, хорошо, что этот порт на PC медленно, но отмирает. Но - долго...

P.S. Ещё можете обратить внимание на сам "свисток", через который вы и общаетесь с компьютером. Иногда помогает просто взять другой "свисток". Там ведь, при всём богатстве выбора, всего 3 основные микросхемы.


Название: Re: QSerial приём данных
Отправлено: sergek от Ноябрь 07, 2020, 13:14
И, хорошо, что этот порт на PC медленно, но отмирает. Но - долго...
Давно не ходил в магазин. И куда сейчас втыкают мышь и клаву?  ;)


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 07, 2020, 13:47
Давно не ходил в магазин. И куда сейчас втыкают мышь и клаву?  ;)
В уши, конечно. Тем более, что их два.:)
На свете ещё овер9000 машин с асинхронным портом. Кстати и порт PS/2 встречается. В основном в военке, но и на гражданке бывают. Если вы суслика не видите, из этого не следует, что его нет.


Название: Re: QSerial приём данных
Отправлено: kuzulis от Ноябрь 07, 2020, 14:15
 Какую то дичь  понаписали, понасоветовали. То отдельные треды, то без сигнала, то какие то слипы, то чото там отмирает у кого то. Наговнокодят а потом плачутся что не работает и что это баги.

Вопрос: а нахрена тогда вам куте вообще? Хоть бы почитали как куте работает, про евент луп, прежде чем говнокодить.

Совет , всегда использовать сигналы и не использовать блокирующие вызовы никогда!


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 07, 2020, 14:51
Совет , всегда использовать сигналы и не использовать блокирующие вызовы никогда!
Ну так ТС и говорил, что нужный сигнал не работает.
К тому же, можно взять прямой (и правильный, видимо) пример от самих разработчиков Qt и убедиться, что сигнал не испускается. Или у них тоже "говнокод"? :)
Могу посоветовать уходить ТС на linux. где всё работает, но он вряд ли захочет. :)


Название: Re: QSerial приём данных
Отправлено: kuzulis от Ноябрь 07, 2020, 15:37
 был один единственный эпичный баг в qt 5.13.0 то ли 5.13.1. И если ТС использует эту версию, то он ССЗБ.


Название: Re: QSerial приём данных
Отправлено: sergek от Ноябрь 07, 2020, 16:02
был один единственный эпичный баг в qt 5.13.0 то ли 5.13.1. И если ТС использует эту версию, то он ССЗБ.
Баг в 5.13.1 и выше. Мне пришлось отъехать на 5.13.0, до сих пор работаю на нем.


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 07, 2020, 17:09
Баг в 5.13.1 и выше. Мне пришлось отъехать на 5.13.0, до сих пор работаю на нем.
Откуда инфа? Интересует линк, конечно
Ну и, собственно, а почему не исправляют, может знаете?


Название: Re: QSerial приём данных
Отправлено: qate от Ноябрь 07, 2020, 17:55
Более того, некоторое время назад я уже наступал на эти грабли.

ты так и не представил рабочий пример с багом, зато ни раз про это написал, что мне о тебе думать ?


Название: Re: QSerial приём данных
Отправлено: qate от Ноябрь 07, 2020, 17:59
объясните пожалуйста как правильно принимать данные

классика: RTFM по все поля https://doc.qt.io/qt-5/qtserialport-creaderasync-example.html


Название: Re: QSerial приём данных
Отправлено: sergek от Ноябрь 07, 2020, 18:29
Откуда инфа? Интересует линк, конечно
Ну и, собственно, а почему не исправляют, может знаете?
Ссылку на багтрекер не искал, но вот следы:
http://www.prog.org.ru/index.php?topic=32505.msg240168#msg240168 (http://www.prog.org.ru/index.php?topic=32505.msg240168#msg240168)


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 07, 2020, 18:37
ты так и не представил рабочий пример с багом, зато ни раз про это написал, что мне о тебе думать ?
Я уже говорил, возьми стандартный пример - баг там будет. Если у тебя он не воспроизводится, то из этого не следует, что другие криворуки.


Название: Re: QSerial приём данных
Отправлено: kuzulis от Ноябрь 07, 2020, 18:48
Цитата: sergek
Я уже говорил, возьми стандартный пример

sergek, Какой пример?

Как уже было сказано ранее, баг с readyRead() был именно в 5.13.1: https://bugreports.qt.io/browse/QTBUG-78086
Всё, точка. Остальное блабла - это просто словестный мусор.

Цитата: tux
Ну и, собственно, а почему не исправляют, может знаете?

tux, что не исправляют? Хватит уже троллить.

PS: Да и некому больше исправлять баги, т.к. нового сопровождающего не нашли, а старый недавно покинул проект.
Если хочешь - бери и исправляй теперь сам.. Опен сорс все-таки. ))

PS: И еще, чтобы при-закрыть разное, скажу, что начиная с версии 5.14.0 больше никаких изменений в qtserialport не было.


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 07, 2020, 19:00
Хватит уже троллить.
Даже не думал. Впрочем, если будет решение - возьму на вооружение. Если нет - есть костыль. :)
Хотя, 7-ки всё меньше, может и не придётся уже...


Название: Re: QSerial приём данных
Отправлено: kuzulis от Ноябрь 07, 2020, 19:04
Цитировать
Хотя, 7-ки всё меньше, может и не придётся уже...

Да нет разницы в 7/8/10-ке.

Цитировать
Впрочем, если будет решение - возьму на вооружение.

Какое решение? Я говорю, что readyRead() работает везде кроме Qt 5.13.1. Что еще непонятно?


Название: Re: QSerial приём данных
Отправлено: sergek от Ноябрь 07, 2020, 20:07
sergek, Какой пример?
Как уже было сказано ранее, баг с readyRead() был именно в 5.13.1: https://bugreports.qt.io/browse/QTBUG-78086
Всё, точка. Остальное блабла - это просто словестный мусор.
Да, 5.13.1, точка. Извини, просто не запомнил, где исправили, т.к. с 5.13.0 не сдвинулся.


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 07, 2020, 20:08
Какое решение? Я говорю, что readyRead() работает везде кроме Qt 5.13.1. Что еще непонятно?
Нормальное решение. Которое работает везде, а не только у вас. :)
Только что проверил - 5.15.1 - баг остался.
P.S. Чип свистка CH340


Название: Re: QSerial приём данных
Отправлено: qate от Ноябрь 07, 2020, 21:02
Только что проверил - 5.15.1 - баг остался.

сможешь выложить пример (багрепорт) с багом или мы должны догадываться от твоих способностях ?



Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 07, 2020, 21:15
сможешь выложить пример (багрепорт) с багом или мы должны догадываться от твоих способностях ?
Экстрасенсорику надо развивать с младенчества! :)
Вот очередная семёрка докачается, покажу пример. Он, кстати, не так уж и далеко ушёл от примера от самой Qt.
P.S. Я ошибся. Работает. Может быть, оно и в самом деле, проблема была только в одной версии Qt.


Название: Re: QSerial приём данных
Отправлено: paibolit от Ноябрь 08, 2020, 13:24
Спасибо всем кто отписался.... Свистков у меня 2 - мой на FTDI, и клиентский на PL2303 - поведение одинаковое. Самый стабильный приём получился при приёме данных по сигналу readReady(). Один из моментов которые я не могу понять это почему этот сигнал появляется только после пользования waitForReadyRead(), но больше всего БЕСИТ !!!!!!!!!!! появление ошибки таймаут после пользования waitForReadyRead(), причём независимо от длительности задержки. Версия QT 5.15.1. Программа проверялась и на 10ке и на 7ке. Железо на 10ке значительно сильнее, но при этом по сигналу readReady() на 10ке всегда принимается исключительно по 1му байту, в то время как на 7ке при приёме пакета 7 байт за один раз залетало и 4 байта(размер буфера и задавал и не задавал) - этот момент также непонятен....
Может комуто мои изыскания будут полезны..........
P.S. Весь гемморой начался после того как рабочая программа с использованием QModbusRtuSerialMaster на I5 не захотела работать на более слабом железе и пришлось связь по MODBUS реализовывать через QSerialPort


Название: Re: QSerial приём данных
Отправлено: sergek от Ноябрь 08, 2020, 14:33
Один из моментов которые я не могу понять это почему этот сигнал появляется только после пользования waitForReadyRead(), ...
Трудно гадать без исходников, но по симптомам - отсутствует цикл обработки событий.


Название: Re: QSerial приём данных
Отправлено: paibolit от Ноябрь 08, 2020, 15:09
Цитировать
Трудно гадать без исходников, но по симптомам - отсутствует цикл обработки событий.
Код в первом посте
http://www.prog.org.ru/index.php?topic=32856.msg243311#msg243311 (http://www.prog.org.ru/index.php?topic=32856.msg243311#msg243311)
 изменение времени задержки проблему появления ошибки таймаута не решают.
Код обработки ошибок:
Код:
    connect(serial, SIGNAL(error(QSerialPort::SerialPortError)),
                this, SLOT(errorSerial(QSerialPort::SerialPortError)));

void SendCom::errorSerial(QSerialPort::SerialPortError err)
{
    qDebug()<<"SendCom Error: "+serial->errorString();//QString::number(err);
}


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 08, 2020, 15:22
Вы бы лучше накидали полный пример, как именно и что вы делаете. Потому что на кусках кода удачно получается только гадать. Как на бараньей лопатке. :)


Название: Re: QSerial приём данных
Отправлено: paibolit от Ноябрь 08, 2020, 17:10
Заголовочный файл нужен ?

mainwindow.cpp
Код:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "sendcom.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

   QString PORT="COM4";
   sendCom.setPORT(PORT);// Устанавливаем номер порта
   if(!sendCom.InitPort())qDebug<<"Что то не получилось с "<<PORT;

   
   qDebug()<<"Получилось подключится к "<<PORT;


}
sendcom.cpp
Код:
#include "sendcom.h"
#include <QDebug>


SendCom::SendCom(QObject *parent) : QObject(parent)//,

{

//qDebug("Potok SendCom telo");
//qDebug()<<"Telo Thread:"<<QString::number((int)QThread::currentThreadId());
}

bool SendCom::InitPort()
{
    if(!InitSerial())return false;

    if(!SendAndRead())
    {
        serial->close();
        return false;
    }
    qDebug()<<PORT<<" Read:"<<QString(m_arrCom.toHex().toUpper());

        serial->close();
        return true;
}

bool SendCom::InitSerial()
{
    qDebug()<<"Init START "<<PORT;
    serial=new QSerialPort(this);
    serial->setPortName(PORT);
    serial->setBaudRate(QSerialPort::Baud38400);
    serial->setDataBits(QSerialPort::Data8);
    serial->setParity(QSerialPort::NoParity);
    serial->setStopBits(QSerialPort::OneStop);
    serial->setFlowControl(QSerialPort::NoFlowControl);

    if(!serial->open(QSerialPort::ReadWrite))
    {
        qDebug()<<"ERROR !!! Не могу открыть порт "<<PORT;
    return false;
    }


    connect(serial, SIGNAL(readyRead()), this, SLOT(read()));
    connect(serial, SIGNAL(error(QSerialPort::SerialPortError)),
                this, SLOT(errorSerial(QSerialPort::SerialPortError)));
    return true;
}

bool SendCom::SendAndRead()
{
   serial->clear();
   w_arrCom.clear();//Очищаем массив перед подготовкой пакета

w_arrCom = QByteArray::fromHex("010404020001913A");


quint8 lenRead=........;//Вычисление длины ответа от устройства


for (quint8 i=0;i<2;i++)//Две попытки отправки запроса и получения ответа
{
    qDebug()<<"Попытка №"<<QString::number(i+1);
  serial->write(w_arrCom);// Запись в последовательный порт

    this->thread()->msleep(qCeil(150));// Засыпаем, ожидая, пока микроконтроллер обработает данные и ответит.
  m_arrCom.clear();//Очищаем буфер перед приёмом данных

serial->waitForReadyRead(300);//Без этой команды данные не приходят в буфер от слова СОВСЕМ)))

      if (m_arrCom.size()==lenRead) break;
      else{
          qDebug<<"Ответ не подходит по длине Bytes read: "<<QString::number(m_arrCom.size())
                  <<" lenRead:"<<QString::number(lenRead);

}
      serial->clear();
}
if (m_arrCom.size()!=lenRead) return false;

return true;
}

void SendCom::read()
{

//qDebug()<< "Доступно: "<<serial->bytesAvailable();
        m_arrCom += serial->readAll();
}

void SendCom::errorSerial(QSerialPort::SerialPortError err)
{
    qDebug()<<"SendCom Error: "+serial->errorString();//QString::number(err);
}

void SendCom::setPORT(QString m_PORT)
{
    if (PORT == m_PORT)
        return;

    PORT = m_PORT;
}


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 08, 2020, 18:42
Заголовочный файл нужен ?
Нет. Догадываюсь, в чём у вас проблема. waitForReadyRead вам нужен тут только для того, чтобы хоть как то отдать время центральному процессору. Тут надо либо по-другому строить архитектуру (чтобы нормально использовать сигналы-слоты) либо в цикле (при ожидании) периодически вызывать QCoreApplication::processEvents.
Ну и, при полном приёме данных (после заполнения буфера полезными данными), лучше взвести какой-нибудь флаг. Либо выпустить сигнал. Хотя тут "на вкус и цвет все фломастеры разные" :)


Название: Re: QSerial приём данных
Отправлено: kuzulis от Ноябрь 08, 2020, 19:26
ЛОЛ  ;D ФЭЙСПАЛМ. Я хз нафига я вообще влез в эту тему.


Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 08, 2020, 19:35
ЛОЛ  ;D ФЭЙСПАЛМ. Я хз нафига я вообще влез в эту тему.
Затем, чтобы написать этот пост. Наверное. :)


Название: Re: QSerial приём данных
Отправлено: qate от Ноябрь 08, 2020, 19:57
bool SendCom::SendAndRead()

не должна функция делать и запись и чтение, разделяй и переписывай код
и никаких sleep и waitForReadyRead - не нужно


Название: Re: QSerial приём данных
Отправлено: sergek от Ноябрь 08, 2020, 20:19
Заголовочный файл нужен ?
Когда здесь пишут о примере, то имеется в виду минимальный проект, с профайлом и всеми заголовочными, и с main.
И надо внимательно читать ответы и советы. Тем более от автора библиотеки. Это на будущее, если здесь останетесь.
Если опять мимо, то - где цикл событий? Ну, например, QCoreApplication::exec()?


Название: Re: QSerial приём данных
Отправлено: paibolit от Ноябрь 08, 2020, 21:18

не должна функция делать и запись и чтение, разделяй и переписывай код
и никаких sleep и waitForReadyRead - не нужно


Поскольку это мой дебют в QT - можно по подробнее: в чем проблема если даю запрос потом пауза и чтение (про GUI не надо рассказывать)

Нет. Догадываюсь, в чём у вас проблема. waitForReadyRead вам нужен тут только для того, чтобы хоть как то отдать время центральному процессору. Тут надо либо по-другому строить архитектуру (чтобы нормально использовать сигналы-слоты) либо в цикле (при ожидании) периодически вызывать QCoreApplication::processEvents.
Ну и, при полном приёме данных (после заполнения буфера полезными данными), лучше взвести какой-нибудь флаг. Либо выпустить сигнал. Хотя тут "на вкус и цвет все фломастеры разные" :)
Может я заблуждаюсь - поправьте, когда данные приходят в COM порт они складываются сначала в буфер винды и выполнение этого процесса никоим образом не касается выполнения QTшного кода, а когда дело у QT доходит до забора данных с буфера COM порта - QT фактически забирает эти данные с памяти (с буфера винды) а не непосредственно с COM порта.

Как бы тема для новичков, но некоторые ответы просто "убивают" :'(



Название: Re: QSerial приём данных
Отправлено: tux от Ноябрь 08, 2020, 21:28
Может я заблуждаюсь - поправьте, когда данные приходят в COM порт они складываются сначала в буфер винды и выполнение этого процесса никоим образом не касается выполнения QTшного кода, а когда дело у QT доходит до забора данных с буфера COM порта - QT фактически забирает эти данные с памяти (с буфера винды) а не непосредственно с COM порта.
Складываться то они складываются, но вот сам сигнал пока обработаться не может - все крутится в цикле и внешние события либо не приходят, либо обработаться не могут. QCoreApplication::processEvents ведь не просто так придумали.
Вообще, в GUI лучше ничего долго в функции не крутить, а нормально сделать обработку сигналов/слотов.


Название: Re: QSerial приём данных
Отправлено: qate от Ноябрь 08, 2020, 22:19
Поскольку это мой дебют в QT - можно по подробнее: в чем проблема если даю запрос потом пауза и чтение (про GUI не надо рассказывать)

В обработчике сигнала - никогда не делай паузы:
1. записал и вышел, жди сигнал чтения
2. получил сигнал чтения - вычитал всё и обработал без пауз

какую книгу/статью ты прочитал про сигналы и слоты прежде чем начать писать на qt ?


Название: Re: QSerial приём данных
Отправлено: paibolit от Ноябрь 08, 2020, 23:45
Всё!!!!!!!! Кажется дошло !!!!!
Спасибо что вытерпели меня ;D Пошёл дерзать - о результате отпишусь