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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Принятие пакета с Com порта  (Прочитано 12258 раз)
Ostapich
Гость
« : Октябрь 29, 2017, 00:12 »

Все привет! Возникла проблема! Необходимо читать с подключенной к USB Ардуинки пакет определенной структуры. Написал программу, если просто поток байтов читать, то все ок. Недавно сел за Qt и немого непривычно. Прошу подсказать.
Привожу код:
PORT_H :
Код:
#ifndef PORT_H
#define PORT_H

#include <QObject>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>

struct Settings {
    QString name;
    qint32 baudRate;
    QSerialPort::DataBits dataBits;
    QSerialPort::Parity parity;
    QSerialPort::StopBits stopBits;
    QSerialPort::FlowControl flowControl;
};

class Port : public QObject
{
    Q_OBJECT

public:

    explicit Port(QObject *parent = 0);

    ~Port();

    QSerialPort thisPort;

    Settings SettingsPort;

signals:

    void finished_Port(); //

    void error_(QString err);

    void outPort(QString data);

public slots:

    void  DisconnectPort();

    void ConnectPort(void);

    void Write_Settings_Port(QString name, int baudrate, int DataBits, int Parity, int StopBits, int FlowControl);

    void process_Port();

    void WriteToPort(QByteArray data);

    void ReadInPort();

private slots:

    void handleError(QSerialPort::SerialPortError error);//

public:

};

#endif // PORT_H


Port.cpp

Код:
#include "port.h"
#include <qdebug.h>

Port::Port(QObject *parent) :
    QObject(parent)
{
}

Port::~Port()
{
    qDebug("By in Thread!");
    emit finished_Port();
}

void Port :: process_Port(){
    qDebug("Hello World in Thread!");
    connect(&thisPort,SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
    connect(&thisPort, SIGNAL(readyRead()),this,SLOT(ReadInPort()));
}

void Port :: Write_Settings_Port(QString name, int baudrate,int DataBits,
                         int Parity,int StopBits, int FlowControl){
    SettingsPort.name = name;
    SettingsPort.baudRate = (QSerialPort::BaudRate) baudrate;
    SettingsPort.dataBits = (QSerialPort::DataBits) DataBits;
    SettingsPort.parity = (QSerialPort::Parity) Parity;
    SettingsPort.stopBits = (QSerialPort::StopBits) StopBits;
    SettingsPort.flowControl = (QSerialPort::FlowControl) FlowControl;
}

void Port :: ConnectPort(void){//
    thisPort.setPortName(SettingsPort.name);
    if (thisPort.open(QIODevice::ReadWrite)) {
        if (thisPort.setBaudRate(SettingsPort.baudRate)
                && thisPort.setDataBits(SettingsPort.dataBits)//DataBits
                && thisPort.setParity(SettingsPort.parity)
                && thisPort.setStopBits(SettingsPort.stopBits)
                && thisPort.setFlowControl(SettingsPort.flowControl))
        {
            if (thisPort.isOpen()){
                error_((SettingsPort.name+ " >> Открыт!\r").toLocal8Bit());
            }
        } else {
            thisPort.close();
            error_(thisPort.errorString().toLocal8Bit());
          }
    } else {
        thisPort.close();
        error_(thisPort.errorString().toLocal8Bit());
    }
}

void Port::handleError(QSerialPort::SerialPortError error)//
{
    if ( (thisPort.isOpen()) && (error == QSerialPort::ResourceError)) {
        error_(thisPort.errorString().toLocal8Bit());
        DisconnectPort();
    }
}//


void  Port::DisconnectPort(){
    if(thisPort.isOpen()){
        thisPort.close();
        error_(SettingsPort.name.toLocal8Bit() + " >> Закрыт!\r");
    }
}
//ot tuta kovuratji!!!
void Port :: WriteToPort(QByteArray data){
    if(thisPort.isOpen()){
        thisPort.write(data);
    }
}
//
void Port :: ReadInPort(){
    QByteArray data;

    data.append(thisPort.readAll());

    outPort(data);

    //((QString)(adr.toInt())).toLatin1().toHex()
}

Окно где происходит настройка порта, в него пока хочу читать значение.
DIALOG_SETTINGS_H:

Код:
#ifndef DIALOG_SETTINGS_H
#define DIALOG_SETTINGS_H
#include "port.h"
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QDialog>

struct packet_big //пакет PC
{
    unsigned char start_byte_one;//в длинном пакете равен 254
    unsigned char start_byte_two;//в длинном пакете равен 232
    unsigned char temp_pomp;//температура охлаждения
    unsigned char on_of_pomp;//on-off насоса (1 или 0)
    unsigned char ex_temp_reactor;//текущая температура в реакторе
    unsigned char current_temp_reactor;//выставленная температура в реакторе
    unsigned char timer_ex;//таймер
    unsigned char tmp;//пока не трогаем
    unsigned char CRC8;//пока не трогаем
    void pask()
    {
        CRC8 = (start_byte_one + start_byte_two + temp_pomp + on_of_pomp + ex_temp_reactor + current_temp_reactor + timer_ex + tmp) / 10;
    }
    /*проверка упаковки*/
    bool test_pask()
    {
        if (CRC8 == ((start_byte_one + start_byte_two + temp_pomp + on_of_pomp + ex_temp_reactor + current_temp_reactor + timer_ex + tmp)) / 10) return 0; //ОК
        return -1; // ошибка
    }
};

namespace Ui {
class Dialog_Settings;
}

class Dialog_Settings : public QDialog
{
    Q_OBJECT

public:
    packet_big packet_one={254, 232, 0, 0, 0, 0, 0, 0, 0};
    explicit Dialog_Settings(QWidget *parent = 0);
    ~Dialog_Settings();
signals:
    void savesettings(QString name, int baudrate, int DataBits, int Parity, int StopBits, int FlowControl);
     void writeData(QByteArray data);
     void send_str();
public slots:
    void on_BtnSave_clicked();
    void checkCustomBaudRatePolicy(int idx);
    void on_cEnterText_returnPressed();
    void Print(QString data);
    void save_str(QString data);

private:
    Ui::Dialog_Settings *ui;
};

#endif // DIALOG_SETTINGS_H


DIALOG_SETTINGS.сpp
Код:
#include "dialog_settings.h"
#include "ui_dialog_settings.h"
#include <QThread>
#include <QString>
#include <qdebug.h>



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

    connect(ui->BaudRateBox, SIGNAL(currentIndexChanged(int)),this, SLOT(checkCustomBaudRatePolicy(int)));
    ui->BaudRateBox->addItem(QLatin1String("9600"), QSerialPort::Baud9600);
    ui->BaudRateBox->addItem(QLatin1String("19200"), QSerialPort::Baud19200);
    ui->BaudRateBox->addItem(QLatin1String("38400"), QSerialPort::Baud38400);
    ui->BaudRateBox->addItem(QLatin1String("115200"), QSerialPort::Baud115200);
    ui->BaudRateBox->addItem(QLatin1String("Custom"));
    // fill data bits
    ui->DataBitsBox->addItem(QLatin1String("5"), QSerialPort::Data5);
    ui->DataBitsBox->addItem(QLatin1String("6"), QSerialPort::Data6);
    ui->DataBitsBox->addItem(QLatin1String("7"), QSerialPort::Data7);
    ui->DataBitsBox->addItem(QLatin1String("8"), QSerialPort::Data8);
    ui->DataBitsBox->setCurrentIndex(3);
    // fill parity
    ui->ParityBox->addItem(QLatin1String("None"), QSerialPort::NoParity);
    ui->ParityBox->addItem(QLatin1String("Even"), QSerialPort::EvenParity);
    ui->ParityBox->addItem(QLatin1String("Odd"), QSerialPort::OddParity);
    ui->ParityBox->addItem(QLatin1String("Mark"), QSerialPort::MarkParity);
    ui->ParityBox->addItem(QLatin1String("Space"), QSerialPort::SpaceParity);
    // fill stop bits
    ui->StopBitsBox->addItem(QLatin1String("1"), QSerialPort::OneStop);
#ifdef Q_OS_WIN
    ui->StopBitsBox->addItem(QLatin1String("1.5"), QSerialPort::OneAndHalfStop);
#endif
    ui->StopBitsBox->addItem(QLatin1String("2"), QSerialPort::TwoStop);
    // fill flow control
    ui->FlowControlBox->addItem(QLatin1String("None"), QSerialPort::NoFlowControl);
    ui->FlowControlBox->addItem(QLatin1String("RTS/CTS"), QSerialPort::HardwareControl);
    ui->FlowControlBox->addItem(QLatin1String("XON/XOFF"), QSerialPort::SoftwareControl);
    connect(ui->cBtnSend,SIGNAL(clicked()),this, SLOT(on_cEnterText_returnPressed()) );

    QThread *thread_New = new QThread;//Создаем поток для порта платы
    Port *PortNew = new Port();//Создаем обьект по классу
    PortNew->moveToThread(thread_New);//помешаем класс  в поток
    PortNew->thisPort.moveToThread(thread_New);//Помещаем сам порт в поток
    connect(thread_New, SIGNAL(started()), PortNew, SLOT(process_Port()));//Переназначения метода run
    connect(PortNew, SIGNAL(finished_Port()), thread_New, SLOT(quit()));//Переназначение метода выход
    connect(thread_New, SIGNAL(finished()), PortNew, SLOT(deleteLater()));//Удалить к чертям поток
    connect(PortNew, SIGNAL(finished_Port()), thread_New, SLOT(deleteLater()));//Удалить к чертям поток
    connect(this,SIGNAL(savesettings(QString,int,int,int,int,int)),PortNew,SLOT(Write_Settings_Port(QString,int,int,int,int,int)));//Слот - ввод настроек!
    connect(ui->BtnSave, SIGNAL(clicked()),PortNew,SLOT(ConnectPort()));
    connect(PortNew, SIGNAL(outPort(QString)), this, SLOT(Print(QString)));//Лог ошибок
    connect(PortNew, SIGNAL(outPort(QString)), this, SLOT(save_str(QString)));//Лог ошибок
    connect(this,SIGNAL(writeData(QByteArray)),PortNew,SLOT(WriteToPort(QByteArray)));

    ui->comboBox->clear();
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        ui->comboBox->addItem(info.portName());
    }
 ui->lcdNumber->display(packet_one.temp_pomp);
    thread_New->start();
}


Dialog_Settings::~Dialog_Settings()
{
    delete ui;
    qDebug("dellit setting");
}

void Dialog_Settings ::on_BtnSave_clicked()
{
    savesettings(ui->comboBox->currentText(), ui->BaudRateBox->currentText().toInt(),ui->DataBitsBox->currentText().toInt(),
                 ui->ParityBox->currentText().toInt(), ui->StopBitsBox->currentText().toInt(), ui->FlowControlBox->currentText().toInt());

    qDebug("save setting");

}


void Dialog_Settings::checkCustomBaudRatePolicy(int idx)
{
    bool isCustomBaudRate = !ui->BaudRateBox->itemData(idx).isValid();
    ui->BaudRateBox->setEditable(isCustomBaudRate);
    if (isCustomBaudRate)
    {
        ui->BaudRateBox->clearEditText();
    }
}


//+++++++++++++[Процедура ввода данных из строки]++++++++++++++++++++++++++++++++++++++++
void Dialog_Settings::on_cEnterText_returnPressed()
{
    QByteArray data; // Текстовая переменная
    data = ui->cEnterText->text().toLocal8Bit(); // Присвоение "data" значения из EnterText
    //data = ui->cEnterText->text().toLocal8Bit().toHex() + '\r';
    writeData(data); // Отправка данных в порт
    Print(data); // Вывод данных в консоль
}
//+++++++++++++[Процедура вывода данных в консоль]++++++++++++++++++++++++++++++++++++++++
void Dialog_Settings::Print(QString data)
{
    ui->consol->textCursor().insertText(data+'\r'); // Вывод текста в консоль
    ui->consol->moveCursor(QTextCursor::End);//Scroll
}


void Dialog_Settings::save_str(QString data)
{
    char* ptr28 = (char* )&packet_one;
    char* qwe2=(char*) &data;
    qDebug("1");
    if (sizeof(data) >= sizeof(packet_big))
       {
           char buf_pump = 0;
           for (size_t i = 0; i < sizeof(packet_big); i++){

               if (i == 0 && data[0] != 254)
               {
                   qDebug("2");
                   i = 0;
                   continue;
               }
               if (i == 1 && data[0] != 232)
               {
                   qDebug("3");
                   i = 0;
                   continue;
               }
               if (i >= 2)
               {
                    qDebug("4");
                    ptr28[i] = qwe2[i];
                   if (i == sizeof(packet_big) - 1)
                   {
                       if (packet_one.test_pask()) //проверяем контрольную сумму
                       {
                            qDebug("5");
                           i = 0;
                       }
                        qDebug("6");
                   }

               }
           }
       
}


так вод, по образу чтения с последовательного порта ардуинки , другой ардуинкой , надо написать всего то одну функцию. Порт формирует массив байт, испускает сигнал, все ок. Связываю этот сигнал со слотом :
Код:
void Dialog_Settings::save_str(QString data)
{
    char* ptr28 = (char* )&packet_one;
    char* qwe2=(char*) &data;
    qDebug("1");
    if (sizeof(data) >= sizeof(packet_big))
       {
           char buf_pump = 0;
           for (size_t i = 0; i < sizeof(packet_big); i++){

               if (i == 0 && data[0] != 254)
               {
                   qDebug("2");
                   i = 0;
                   continue;
               }
               if (i == 1 && data[0] != 232)
               {
                   qDebug("3");
                   i = 0;
                   continue;
               }
               if (i >= 2)
               {
                    qDebug("4");
                    ptr28[i] = qwe2[i];
                   if (i == sizeof(packet_big) - 1)
                   {
                       if (packet_one.test_pask()) //проверяем контрольную сумму
                       {
                            qDebug("5");
                           i = 0;
                       }
                        qDebug("6");
                   }

               }
           }
       
}


Но ничего не происходит. Подскажите что не так делаю. Я вообще программирование самостоятельно изучаю, поэтому за код строго не судите. Топорно, но на ардуинке все работает.


Заранее спасибо
Записан
Ostapich
Гость
« Ответ #1 : Октябрь 29, 2017, 00:17 »

Может поменять как то типы  данных структуры? я понимаю что решение проблемы простое, но хоть убейте не вижу...
Записан
Ostapich
Гость
« Ответ #2 : Октябрь 29, 2017, 09:21 »

Массив который читается с потока, почему то всегда 4 байта весит, не увеличивается.... короче тупик пока...)
Записан
Mikhail
Программист
*****
Offline Offline

Сообщений: 586


Просмотр профиля
« Ответ #3 : Октябрь 29, 2017, 13:34 »

А не пробовали читать из порта по приходу сигнала о наличии в нем данных. Данные приходят в порт неравномерно и количество байт в блоке не определено. Прочитав один блок, надо быть готовым читать остальные. И все это по сигналам.
Записан
Ostapich
Гость
« Ответ #4 : Октябрь 29, 2017, 14:02 »

Прошу прощения, но если сигнал из порта приходит, значит данные есть. Я правильно понимаю? Или прошу поподробнее....
Записан
Ostapich
Гость
« Ответ #5 : Октябрь 29, 2017, 14:04 »

Как я понял Port :: ReadInPort() каждый раз читает по одному байту, хотя если в дебаг выводить QSerialPort :: bytesAvailable () , то там 200 слишним байт, но если выводить data.size() , то там всегда 4 байта, ничего не пойму откуда ноги растут. На Ардуинке этот алгоритм работает, тут я так понял проблема с типами данных и с поочередностью поступления пакета. На ардуинке разобрался, тут что то не пойму.
Записан
titan83
Гость
« Ответ #6 : Октябрь 29, 2017, 17:30 »

Здорова, ты упускаешь такой момент: на ардуино нет буферизации (не уверен, но почти 100%), т.е. все что поступает одним физическим "пакетом" сразу же и доступно. На "больших братьях" с ОС все немного иначе: тут буферы, уведомления от драйверов аппаратуры... Поэтому ты не можешь контролировать сколько именно байт отдаст драйвер твоей программе.
Короче, тебе надо отслеживать, что пакет, который ты ожидаешь пришел целиком, его надо где-то "собирать".
Т.е. заведи не локальный QByteArray и в него делай append каждый раз в функции ReadInPort (почему "In"Тогда уж "From"). Когда поймешь, что пришло все, что ожидал (нужная комбинация байт или таймаут, или что там в твоем протоколе), то тогда уже передавай собранный массив дальше, не забыв его очистить для следующего сеанса.

Ну и отвыкай от char'ов))
Записан
Ostapich
Гость
« Ответ #7 : Октябрь 29, 2017, 17:41 »

Так, все по порядку. Весь алгоритм вычленения пакета я делаю в слоте ReadInPort ( сейчас приеду домой, переименую). Я создаю  QByteArray в самом классе  порта, потом когда вызывается слот по сигналу readeread( как ты сказал приехать может сколько угодно байт, одному богу известно), я добавляю в массив данные и смотрю что в нем лежит. А если придет меньше , чем хотя бы первые два стартовых байта?мастерить конечный автомат? И что вместо char? И вообще был бы благодарен за псевдокод..)
Записан
Ostapich
Гость
« Ответ #8 : Октябрь 29, 2017, 17:49 »

Или если пришло меньше чем размер нужного нам пакета, положить в массив и ждать еще остаток?
Записан
Ostapich
Гость
« Ответ #9 : Октябрь 29, 2017, 17:55 »

Как я себе представил: Приходит пакет неизвестного размера, мы его запихиваем в массив, смотрим , если меньше того сколько нам нужно , то выходим из слота и ждем следующего, если больше, то в цикле режем его на нужные части и запихиваем в локальный массив, который отправляем вызовом сигнала, если что то осталось, повторяем пока станет меньше или ничего не останется?
Записан
titan83
Гость
« Ответ #10 : Октябрь 29, 2017, 17:57 »

Или если пришло меньше чем размер нужного нам пакета, положить в массив и ждать еще остаток?
Видишь ли, есть разные признаки "законченности" пакета: определенный размер, набор неких байт в конце пакета, временной интервал после пакета.
Нужно понять, что у тебя.
Вот пример ожидания по таймауту:
Код:
   if (_serialPort.bytesAvailable() > 0) {
        if (_reciveData) {
            _inputData.append(_serialPort.readAll());
            _finishSerialReadingTimer.start(100);
        }
    }
Здесь _inputData - как раз QByteArray, определенный в классе. В него дописывают все пришедшие данные, а когда 100мс ничего не приходит, то вызывается, слот по сигналу timeout() от _finishSerialReadingTimer и там этот массив уже обрабатывается.
Записан
Ostapich
Гость
« Ответ #11 : Октябрь 29, 2017, 18:01 »

Ну у меня есть только размер и первые два стартовых байта, в конце идет контрольная сумма. Т.е. Если я в ардуино настрою что пакеты отправляются через 100мс, у меня будет еще дополнительны параметр. Ок.
Записан
titan83
Гость
« Ответ #12 : Октябрь 29, 2017, 18:08 »

Ну у меня есть только размер и первые два стартовых байта, в конце идет контрольная сумма. Т.е. Если я в ардуино настрою что пакеты отправляются через 100мс, у меня будет еще дополнительны параметр. Ок.
Зачем тебе время, если известен размер пакета и стартовые байты? Используй их для приема.
Записан
Ostapich
Гость
« Ответ #13 : Октябрь 29, 2017, 18:16 »

Ок. Отпишусь по результатам...
Записан
Ostapich
Гость
« Ответ #14 : Октябрь 30, 2017, 21:00 »

Товарищи, что не так!?
Код:
void Port :: ReadInPort(){
    if(thisPort.bytesAvailable()>0){
        QByteArray tmp;
        in_data.append(thisPort.readAll());
        if(in_data.size()>=sizeof(packet_big)){
            qDebug()<<"1";
            for(size_t i=0;i<in_data.size();i++){
                qDebug()<<"2";
                if(in_data[i]==254){
                    qDebug()<<"3";
                     qDebug()<<"  "<<in_data[i];
                    if(in_data[i+1]==232){
                        qDebug()<<"4";
                        qDebug()<<"  "<<in_data[i+1];
                        if(in_data.size()>=sizeof(packet_big)){
                            qDebug()<<"5";
                           tmp=in_data.mid(i,sizeof(packet_big)-1);
                           in_data.remove(0,i+(sizeof(packet_big)-1));
                           qDebug()<<" "<<tmp;
                           emit Send_Data(tmp);
                        }
                        else{
                            qDebug()<<"6";
                            in_data.remove(0,i);
                            break;
                        }
                    }
                }
            }
        }
    }
}
ПО дебагу все if проходит, доходит до 5. но когда пытаюсь вывести через дебаг массив, белеберду выводит :  "\xFE\xE8\x00\x00\x00\x00\x00\x00", почему пустые данные , а заполнены только 2.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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