Russian Qt Forum
Ноябрь 23, 2024, 00:52 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: прием/отправка по rs232 в реалтайм  (Прочитано 7302 раз)
lenovo2014
Гость
« : Декабрь 15, 2014, 08:08 »

всем привет. появилась задача приема/отправки сообщений по последовательному порту. Интрефейс rs232 является асинхронным, следовательно нужно посадить порт на прослушку. Данные приходят почти что непрерывно. В данный момент реализовал это вот так:
конектим сигнал
Код:
serialportthread_2::serialportthread_2(QObject *parent) :
    QThread(parent)
{
    connect(&this->port,SIGNAL(readyRead()),this,SLOT(receive()));

}

Код:
void serialportthread_2::run(){
    if(open()){
        while(1){
        port.waitForReadyRead(100);
        this->msleep(100);
        }
       }
    exec();
}

Код:
bool serialportthread_2::receive(){
    port.read(&data[0],30);
    // далее вытаскиваю данные
   port.reset(); // если без этой строчки - через некоторое время программа виснет на строках   [b]exec()[/b] либо [b]port.read(&data[0],30)[/b]
}

вроде все работает, но мне кажется, что это криворукий способ.
может кто подскажет как пограмотнее решить задачу?
зы: также пробовал такой вариант:
Код:
void serialportthread_2::run(){
    if(open()){
        port.waitForReadyRead(-1);

       }
    exec();
}
в этом случае программа вешается через некоторое время
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #1 : Декабрь 15, 2014, 10:59 »

ну во первых зачем использовать одновременно waitFor... и сигнал readyRead()?
Первые функции следует использовать при блокирующих вызовах, а сигнал при асинхронной работе.
Во вторых вы не проверяете bytesAvailable(). Ну и не помешало бы вам глянуть простые примеры при работе с сокетами. Хотя с ком портом не работал в Qt, так что конкретно сказать не могу.
Если вы работаете в linux, то наверное проще будет работать через стандартные файловые функции.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #2 : Декабрь 15, 2014, 11:19 »

1. В корне неверная работа с тредами (если они действительно нужны). Поэтому все и виснет. Погугли. Подмигивающий
2. Достаточно и желательно только использовать связку readyRead() && receive() без всяких waitForXX() и msleep(100)..
3. Треды не нужны. Использовать нужно только если слишком долго осуществляется парсинг данных.

В итоге - колбаса Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
lenovo2014
Гость
« Ответ #3 : Декабрь 15, 2014, 11:45 »

1. В корне неверная работа с тредами (если они действительно нужны). Поэтому все и виснет. Погугли. Подмигивающий
2. Достаточно и желательно только использовать связку readyRead() && receive() без всяких waitForXX() и msleep(100)..
3. Треды не нужны. Использовать нужно только если слишком долго осуществляется парсинг данных.

В итоге - колбаса Улыбающийся
сделал используя связку readyRead() && receive() ; все работает, но через некоторе время, когда число port.bytesAvailable() превышает некий порог, и ,я так понимаю, из-за переполнения буфера , программа виснет. Существует ли способ сбросить буфер ?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #4 : Декабрь 15, 2014, 11:58 »

По умолчанию нет никакого ограничения на размер буфера (по умолчанию он бесконечный Улыбающийся ).
Если нужно ограничение, то нужно установить setReadBufferSize(size > 0).

Скорее всего что-то делаешь не так. Приведи код.
Записан

ArchLinux x86_64 / Win10 64 bit
lenovo2014
Гость
« Ответ #5 : Декабрь 15, 2014, 12:21 »

По умолчанию нет никакого ограничения на размер буфера (по умолчанию он бесконечный Улыбающийся ).
Если нужно ограничение, то нужно установить setReadBufferSize(size > 0).

Скорее всего что-то делаешь не так. Приведи код.
Код:
#include "serialportthread_2.h"
#include "mainwidget.h"

serialportthread_2::serialportthread_2(QObject *parent) :
    QThread(parent)
{
    connect(&this->port,SIGNAL(readyRead()),this,SLOT(receive()));

}
void serialportthread_2::run(){

    if(open()){

        }
    else{
        emit response_2("can't open serial port");
    }
    exec();

}
bool serialportthread_2::open(){
    //port.setPortName("/dev/ttyMI3");
    port.setPortName("/dev/ttyUSB0");
    if(port.open(QIODevice::ReadWrite)){
    port.setBaudRate(QSerialPort::Baud19200);
    port.setDataBits(QSerialPort::Data8);
    //port.setParity(QSerialPort::NoParity);
    port.setStopBits(QSerialPort::OneStop);
    return true;
    }
    else{
        return false;
    }

}
bool serialportthread_2::close(){
    port.close();
}
bool serialportthread_2::receive(){
            port.read(&data[0],30); // зависает на этой строчке
            ...
            QByteArray b;
            b.append(&data[i],12);
            QString msg = b.toHex();
            emit response_2(msg);
}
bool serialportthread_2::send(){
    if(port.write(komanda,n_k))

}


зы : это происходит только при непрерывном потоке данных от устройства. в режиме одиночных команд все нормально работает
Записан
Mikhail
Программист
*****
Offline Offline

Сообщений: 587


Просмотр профиля
« Ответ #6 : Декабрь 15, 2014, 14:53 »

Не увидел где определена data и ее размер. Может быть переполнение.
Где проверка количества пришедших байт?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #7 : Декабрь 15, 2014, 19:05 »

lenovo2014,

Да елки зеленые, почитай про работу с QThread уже. Или не используй QThread если не умеешь.
Записан

ArchLinux x86_64 / Win10 64 bit
lenovo2014
Гость
« Ответ #8 : Декабрь 15, 2014, 19:16 »

Не увидел где определена data и ее размер. Может быть переполнение.
Где проверка количества пришедших байт?
char data[100]; // это объявление массива
port.read(&data[0],30); // считываю 30 байт, проверял в дебаг режиме
Записан
lenovo2014
Гость
« Ответ #9 : Декабрь 15, 2014, 19:17 »

lenovo2014,

Да елки зеленые, почитай про работу с QThread уже. Или не используй QThread если не умеешь.
ты конкретно скажи что не так, все же по документации я сделал
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #10 : Декабрь 15, 2014, 19:36 »

Цитировать
ты конкретно скажи что не так, все же по документации я сделал

Не хочу. Я уже посоветовал все что нужно.
Записан

ArchLinux x86_64 / Win10 64 bit
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #11 : Декабрь 16, 2014, 11:52 »

во первых каждый раз при вызове слота чтения данных с сокета/порта следует проверить сколько данных в буфере. достаточно ли их для чтения или стоит еще подождать.
очевидно что у тебя зависает на функции read, потому что в буфере скорее всего недостаточно данных (нет 30 байт). поэтому если известен за ранее объем ожидаемых данных, стоит дождаться его.
например так

Код:

void MyObject::connected()
{
 offset = 0LL;
}

void MyObject::readyData()
{
 QTcpSocket * s = qobject_cast<QTcpSocket*>(sender()); //при условии что один поток, можно вообще напрямую обращаться к внутренним данным если сокет/порт один на объект
 qint64 bytesCount = s->bytesAvailable();
 if(bytesAvailable<neededSize) //needed size - размер ожидаемых данных, как его получить вам решать (константа или получать как то в заголовках пакетов)
  return;
 qint64 readBytes = s->read(&data[offset],neededSize);
 if(readBytes<0LL)
 {
 //обработка ошибки чтения
 }
 else
 if(readBytes==0LL)
 {
 //сокет был закрыт на удаленной стороне, на счёт ком порта не знаю но лучше проверить
 }
 else
 offset += readBytes //если у вас буфер на несколько пакетов или читаете частями
 if(offset==desiredPacketSize) //получены данные целиком
 {
 emit dataReady(&data[0]); //сигналим о полном приеме пакета с адресом буфера, или передавать QByteArray(data);
 }
}

Это не полный код, но суть такая.
Если у вас данные всегда одного размера все намного проще. Если размер данных палвающий, то каким то образом следует сначала передать размер пакета, а потом сами данные.
Как это сделать решать вам, я для этого в начале данных всегда передаю фиксированную структуру данных типа
Код:
struct Header {
quint32 signature;
quint32 packetSize;
... //прочие полезные данные
};
И данные будут идти тогда так
Код:
[Header][Data .....][Header][Data ...]...
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.053 секунд. Запросов: 22.