Название: Принятие пакета с Com порта
Отправлено: 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"); }
} } }
Но ничего не происходит. Подскажите что не так делаю. Я вообще программирование самостоятельно изучаю, поэтому за код строго не судите. Топорно, но на ардуинке все работает. Заранее спасибо
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 29, 2017, 00:17
Может поменять как то типы данных структуры? я понимаю что решение проблемы простое, но хоть убейте не вижу...
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 29, 2017, 09:21
Массив который читается с потока, почему то всегда 4 байта весит, не увеличивается.... короче тупик пока...)
Название: Re: Принятие пакета с Com порта
Отправлено: Mikhail от Октябрь 29, 2017, 13:34
А не пробовали читать из порта по приходу сигнала о наличии в нем данных. Данные приходят в порт неравномерно и количество байт в блоке не определено. Прочитав один блок, надо быть готовым читать остальные. И все это по сигналам.
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 29, 2017, 14:02
Прошу прощения, но если сигнал из порта приходит, значит данные есть. Я правильно понимаю? Или прошу поподробнее....
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 29, 2017, 14:04
Как я понял Port :: ReadInPort() каждый раз читает по одному байту, хотя если в дебаг выводить QSerialPort :: bytesAvailable () , то там 200 слишним байт, но если выводить data.size() , то там всегда 4 байта, ничего не пойму откуда ноги растут. На Ардуинке этот алгоритм работает, тут я так понял проблема с типами данных и с поочередностью поступления пакета. На ардуинке разобрался, тут что то не пойму.
Название: Re: Принятие пакета с Com порта
Отправлено: titan83 от Октябрь 29, 2017, 17:30
Здорова, ты упускаешь такой момент: на ардуино нет буферизации (не уверен, но почти 100%), т.е. все что поступает одним физическим "пакетом" сразу же и доступно. На "больших братьях" с ОС все немного иначе: тут буферы, уведомления от драйверов аппаратуры... Поэтому ты не можешь контролировать сколько именно байт отдаст драйвер твоей программе. Короче, тебе надо отслеживать, что пакет, который ты ожидаешь пришел целиком, его надо где-то "собирать". Т.е. заведи не локальный QByteArray и в него делай append каждый раз в функции ReadInPort (почему "In"Тогда уж "From"). Когда поймешь, что пришло все, что ожидал (нужная комбинация байт или таймаут, или что там в твоем протоколе), то тогда уже передавай собранный массив дальше, не забыв его очистить для следующего сеанса.
Ну и отвыкай от char'ов))
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 29, 2017, 17:41
Так, все по порядку. Весь алгоритм вычленения пакета я делаю в слоте ReadInPort ( сейчас приеду домой, переименую). Я создаю QByteArray в самом классе порта, потом когда вызывается слот по сигналу readeread( как ты сказал приехать может сколько угодно байт, одному богу известно), я добавляю в массив данные и смотрю что в нем лежит. А если придет меньше , чем хотя бы первые два стартовых байта?мастерить конечный автомат? И что вместо char? И вообще был бы благодарен за псевдокод..)
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 29, 2017, 17:49
Или если пришло меньше чем размер нужного нам пакета, положить в массив и ждать еще остаток?
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 29, 2017, 17:55
Как я себе представил: Приходит пакет неизвестного размера, мы его запихиваем в массив, смотрим , если меньше того сколько нам нужно , то выходим из слота и ждем следующего, если больше, то в цикле режем его на нужные части и запихиваем в локальный массив, который отправляем вызовом сигнала, если что то осталось, повторяем пока станет меньше или ничего не останется?
Название: Re: Принятие пакета с Com порта
Отправлено: titan83 от Октябрь 29, 2017, 17:57
Или если пришло меньше чем размер нужного нам пакета, положить в массив и ждать еще остаток?
Видишь ли, есть разные признаки "законченности" пакета: определенный размер, набор неких байт в конце пакета, временной интервал после пакета. Нужно понять, что у тебя. Вот пример ожидания по таймауту: if (_serialPort.bytesAvailable() > 0) { if (_reciveData) { _inputData.append(_serialPort.readAll()); _finishSerialReadingTimer.start(100); } }
Здесь _inputData - как раз QByteArray, определенный в классе. В него дописывают все пришедшие данные, а когда 100мс ничего не приходит, то вызывается, слот по сигналу timeout() от _finishSerialReadingTimer и там этот массив уже обрабатывается.
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 29, 2017, 18:01
Ну у меня есть только размер и первые два стартовых байта, в конце идет контрольная сумма. Т.е. Если я в ардуино настрою что пакеты отправляются через 100мс, у меня будет еще дополнительны параметр. Ок.
Название: Re: Принятие пакета с Com порта
Отправлено: titan83 от Октябрь 29, 2017, 18:08
Ну у меня есть только размер и первые два стартовых байта, в конце идет контрольная сумма. Т.е. Если я в ардуино настрою что пакеты отправляются через 100мс, у меня будет еще дополнительны параметр. Ок.
Зачем тебе время, если известен размер пакета и стартовые байты? Используй их для приема.
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 29, 2017, 18:16
Ок. Отпишусь по результатам...
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 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.
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 30, 2017, 21:13
Забыл обнулить i в последнем условии: if(in_data.size()>=sizeof(packet_big)){ tmp=in_data.mid(i,sizeof(packet_big)-1); in_data.remove(0,i+(sizeof(packet_big)-1)); qDebug()<<"5 "<<in_data.size()<<" i "<<i << " " << tmp; i=0; emit Send_Data(tmp);
Но все равно не помогает)
Название: Re: Принятие пакета с Com порта
Отправлено: titan83 от Октябрь 30, 2017, 21:14
У меня пошла кровь из глаз... Как я могу это развидеть??? А если серьезно, то телепатов тут нет. Не делай такую каку, не надо 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){
Есть вариант: if (in_data.indexOf(QByteArray::fromHex("FEE8")) > -1) { bla-bla }
Ну и выложи сюда дебаг вывод подробный, что там в in_data оказывается хотя бы на шаге "1", домысливать за тебя не хочу, честно. ЗЫ Хорош копипастить с ардуино: не надо size_t, лучше (unsigned) int.
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 30, 2017, 21:21
Переведите пожалуйста: in_data.indexOf(QByteArray::fromHex("FEE8") ... Прошу прощения, как могу, стараюсь исправиться ))
Название: Re: Принятие пакета с Com порта
Отправлено: titan83 от Октябрь 30, 2017, 21:33
Переведите пожалуйста: in_data.indexOf(QByteArray::fromHex("FEE8") ... Прошу прощения, как могу, стараюсь исправиться ))
Чувак, твой код - это сплошная боль. Но я так же говнокодил лет 7 назад. Ты сделай все заново, но: 1. Без копипасты с ардуины. 2. Без потоков, тебе это тут не надо. инфа 146%. 3. Почитай справку, и ты поймешь, что in_data.indexOf(QByteArray::fromHex("FEE8") спасет тебя от трех уровней вложенности как минимум. 4. Делай все по шагам: сначала просто читай все пакет. Убедись, что приходит то, что отправлено. Потом уже начинай менять пакет. 5. Срочно убирай всю эту арифметику указателей. Кодируй, используя ссылки, а не указатели, будет намного надежнее. Сейчас у тебя сделано очень плохо: месиво из структур, классов, у которых ты что-то меняешь, используя указатели. Ну и я так и не увидел отладочного вывода, который бы показывал, что пакет с ардуино пришел.
Название: Re: Принятие пакета с Com порта
Отправлено: titan83 от Октябрь 30, 2017, 21:37
но когда пытаюсь вывести через дебаг массив, белеберду выводит : "\xFE\xE8\x00\x00\x00\x00\x00\x00" packet_big packet_one={254, 232, 0, 0, 0, 0, 0, 0, 0};
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 30, 2017, 22:10
Да я уже понял, что все ок. Прошу прощения за причиненную боль, но пока как могу, буду исправляться, спасибо за совет)
Название: Re: Принятие пакета с Com порта
Отправлено: titan83 от Октябрь 30, 2017, 22:12
То, что критику воспринимаешь адекватно - это тебе большой плюс. Думаю, дальше сам вывезешь.
Название: Re: Принятие пакета с Com порта
Отправлено: Ostapich от Октябрь 30, 2017, 23:31
Все разобрался, принимает то что надо! Спасибо за помощь. Все ошибки буду исправлять чуть позже, когда работать все будет, это пока в приоритете , когда в нормальный вид приведу, выложу тут, но советы учту.
Название: Re: Принятие пакета с Com порта
Отправлено: kuzulis от Октябрь 31, 2017, 12:37
> вид приведу, выложу тут
не, не надо, оставь у себя
|