QextSerialPort и потоки
Пишу программу, которая должна забирать данные с приборов по
последовательному порту (8 цифровых датчиков веса производства HBM, если
это важно). Для общения с портом используется QextSerialPort. Чтобы
ожидание ответов не тормозило всю программу, создан второй поток
(производный от QThread). В нём кроме порта также создаётся QTimer,
сигнал от которого собственно и вызывает функции опроса. Оба объекта
создаются уже в функции run(), которая, судя по документации, и должна
выполняться в отдельном потоке. Заканчивается она вызовом exec(), чтобы
сигналы от таймера обрабатывались. И всё было бы нормально, поток когда
надо запускается, завершается, но ожидание ответов всё равно тормозит
весь процесс. В чём может быть причина, и как это исправить? Попробовал
собрать эту же программу под оффтопиком (XP SP2) - там не тормозит, всё
чудесно работает. QT 4.3.0 ставил из исходников в /usr/local (если что
не так, могу и пересобрать), система - Sarge. Если пройдут вложения - в
них исходник этого модуля.
#include "serial.h"
int port_fd;
//int must_stop;
//int f_rx, f_timeout;
//u_int8_t msg1 [100];
loadcells::loadcells(clbDialog *c1)
{
// must_stop=0;
clb1=c1;
setWindowTitle (tr("Comm. setup"));
editPortName = new QLineEdit(this);
editN1 = new QLineEdit(this);
editN2 = new QLineEdit(this);
editN3 = new QLineEdit(this);
editN4 = new QLineEdit(this);
editN5 = new QLineEdit(this);
editN6 = new QLineEdit(this);
editN7 = new QLineEdit(this);
editN8 = new QLineEdit(this);
labelPortName = new QLabel(tr("Serial port name"), this);
labelNN = new QLabel(tr("Adresses of loadcells"), this);
labelP1 = new QLabel(tr("Platform 1"), this);
labelP2 = new QLabel(tr("Platform 2"), this);
labelN1 = new QLabel(tr("Loadcell's N1 adress"), this);
labelN2 = new QLabel(tr("Loadcell's N2 adress"), this);
labelN3 = new QLabel(tr("Loadcell's N3 adress"), this);
labelN4 = new QLabel(tr("Loadcell's N4 adress"), this);
labelN5 = new QLabel(tr("Loadcell's N5 adress"), this);
labelN6 = new QLabel(tr("Loadcell's N6 adress"), this);
labelN7 = new QLabel(tr("Loadcell's N7 adress"), this);
labelN8 = new QLabel(tr("Loadcell's N8 adress"), this);
buttonStart = new QPushButton(tr("Start comm."), this);
buttonStop = new QPushButton(tr("Stop comm."), this);
buttonSave = new QPushButton(tr("Save"), this);
buttonClose = new QPushButton(tr("Close"), this);
checkAutostart = new QCheckBox(tr("Auto start comm."), this);
// port1 = new QextSerialPort();
layout1 = new QGridLayout(this);
tc1 = new threadComm(this);
loadSettings();
layout1->setSpacing(20);
layout1->addWidget(labelNN,0,2);
layout1->addWidget(labelP1,1,0);
layout1->addWidget(labelP2,1,4);
layout1->addWidget(labelN1,2,0);
layout1->addWidget(editN1,2,1);
layout1->addWidget(editN2,2,2);
layout1->addWidget(labelN2,2,3);
layout1->addWidget(labelN3,3,0);
layout1->addWidget(editN3,3,1);
layout1->addWidget(editN4,3,2);
layout1->addWidget(labelN4,3,3);
layout1->addWidget(labelN5,2,4);
layout1->addWidget(editN5,2,5);
layout1->addWidget(editN6,2,6);
layout1->addWidget(labelN6,2,7);
layout1->addWidget(labelN7,3,4);
layout1->addWidget(editN7,3,5);
layout1->addWidget(editN8,3,6);
layout1->addWidget(labelN8,3,7);
layout1->addWidget(labelPortName, 4, 0);
layout1->addWidget(editPortName, 4, 1);
layout1->addWidget(checkAutostart, 5, 0);
layout1->addWidget(buttonStart, 6, 0);
layout1->addWidget(buttonStop, 6, 1);
layout1->addWidget(buttonSave, 6, 6);
layout1->addWidget(buttonClose, 6, 7);
connect(buttonClose, SIGNAL(clicked()), this, SLOT(close()));
connect(buttonSave, SIGNAL(clicked()), this, SLOT(saveSettings()));
connect(buttonStart, SIGNAL(clicked()), tc1, SLOT(startC()));
connect(buttonStop, SIGNAL(clicked()), tc1, SLOT(stopC()));
connect(tc1, SIGNAL(updated()), this, SLOT(updatedP()));
if (checkAutostart->checkState()==Qt::Checked) tc1->startC();
// connect(this, SIGNAL(tcStop()), tc1, SLOT(stop()));
}
void loadcells::updatedP()
{
emit updated();
}
QString loadcells::getPortName()
{
QString s1 = editPortName->text();
return s1;
}
void loadcells::loadSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, "CMA", "QVD"); //Debug
// QSettings s1(QSettings::IniFormat, QSettings::SystemScope, "CMA", "QVD"); //Release
editN1->setText(settings.value("comm/adress1", "0").toString());
editN2->setText(settings.value("comm/adress2", "0").toString());
editN3->setText(settings.value("comm/adress3", "0").toString());
editN4->setText(settings.value("comm/adress4", "0").toString());
editN5->setText(settings.value("comm/adress5", "0").toString());
editN6->setText(settings.value("comm/adress6", "0").toString());
editN7->setText(settings.value("comm/adress7", "0").toString());
editN8->setText(settings.value("comm/adress8", "0").toString());
editPortName->setText(settings.value("comm/portName", " ").toString());
if(settings.value("comm/autostart", "0").toString() == "0")checkAutostart->setCheckState(Qt::Unchecked);
if(settings.value("comm/autostart", "0").toString() == "2")checkAutostart->setCheckState(Qt::Checked);
}
void loadcells::saveSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, "CMA", "QVD"); //Debug
// QSettings s1(QSettings::IniFormat, QSettings::SystemScope, "CMA", "QVD"); //Release
settings.setValue("comm/adress1", editN1->text());
settings.setValue("comm/adress2", editN2->text());
settings.setValue("comm/adress3", editN3->text());
settings.setValue("comm/adress4", editN4->text());
settings.setValue("comm/adress5", editN5->text());
settings.setValue("comm/adress6", editN6->text());
settings.setValue("comm/adress7", editN7->text());
settings.setValue("comm/adress8", editN8->text());
settings.setValue("comm/portName", editPortName->text());
settings.setValue("comm/autostart", checkAutostart->checkState ());
}
//int init_port(char* portname) {
// port_fd = open (portname, O_RDWR | O_NOCTTY | O_NDELAY);
// if (port_fd == -1) return -1;
// fcntl(port_fd, F_SETFL, 0);
// struct termios options;
// tcgetattr(port_fd, &options);
// cfsetispeed(&options, B115200);
// cfsetospeed(&options, B115200);
// options.c_cflag |= (CLOCAL | CREAD);
// options.c_cflag &= ~CSIZE;
// options.c_cflag |= CS8;
// options.c_cflag &= ~PARENB;
// options.c_cflag &= ~CSTOPB;
///* options.c_cflag |= CRTSCTS; */
// options.c_cflag &= ~CRTSCTS;
// options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN);
// options.c_oflag &= ~OPOST;
// options.c_cc[VMIN] = 0;
// options.c_cc[VTIME] = 10;
// options.c_iflag &= ~(IXON | IXOFF | IXANY | INLCR | ICRNL);
// options.c_iflag &= ~(INPCK | ISTRIP | PARMRK | IGNCR);
// options.c_iflag |= IGNPAR;
// tcsetattr(port_fd, TCSANOW, &options);
// tcflush (port_fd, TCIOFLUSH);
// return 0;
//}
//void close_port (void) { close (port_fd); }
//void* u_timeout(){
//// f_timeout = 1;
// pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
// int count = 0;
// while ((count < 1000) && (f_rx != 1)) { usleep (500); count++; };
//// usleep (500000);
// f_timeout = 0;
// return NULL;
//}
//void* u_read(){
// f_rx = 0;
// int count_bytes=0;
// msg1[0] = 1;
// while ((f_timeout == 1)&&(count_bytes < msg1[0]+3)){
// int len1 = read (port_fd, &msg1[count_bytes], 1);
//// if (len1 != -1)fprintf (stdout, "\n msg1[%X] = %X", count_bytes, msg1[count_bytes]);
// if ((len1 != -1) && (count_bytes <= 30)) count_bytes += len1;
// }
//// fprintf (stdout, "\n count_bytes = %X, f_timeout = %X", count_bytes, f_timeout);
//// }
// if (f_timeout == 0) f_rx = -1;
// else f_rx = 1;
// return NULL;
//}
//Sending request, whaiting and testing answer
//Return codes:
//0 - OK
//-1 - Time-out
//-2 - Checksum error
//*/
//int req_ans(u_int8_t* req) {
// pthread_t thread_read, thread_timeout;
// f_timeout = 1;
// pthread_create (& thread_read, NULL, &u_read, NULL);
// pthread_create (& thread_timeout, NULL, &u_timeout, NULL);
// int req_l = req[0]+3;
//// fprintf(stdout, "\n req = %X, %X, %X, %X, %X, %X, %X, %X, %X,", req[0], req[1], req[2], //req[3], req[4], req[5], req[6], req[7], req[8]);
//// fprintf(stdout, "\n req_l = %X", req_l);
// int res = write (port_fd, req, req_l);
// if (res == -1) {
// pthread_join (thread_read, NULL);
// pthread_join (thread_timeout, NULL);
// return -1;
// }
//// if (ans_l > 2) sleep (1);
//// res = read (port_fd, ans, ans_l);
// pthread_join (thread_read, NULL);
//// if (f_rx == 0) pthread_cancel (thread_timeout);
// pthread_join (thread_timeout, NULL);
//// fprintf(stdout, "\n f_timeout = %X, f_rx = %X", f_timeout, f_rx);
//// if (f_rx != 1) return -1;
//// if (test_cs_msg (msg1) == 0) return 0;
//// return -2;
// return -2;
//}
void threadComm::startC()
{
start(QThread::LowestPriority);
emit started();
}
threadComm::threadComm(loadcells *p2)
{
parent=p2;
}
void threadComm::stopC()
{
qDebug("Stop signal");
exit(0);
// emit tcStop();
if(wait(5000)==TRUE)qDebug("Normal exit");
else qDebug("Timeout");
emit stopped();
}
QString loadcells::getNum(int i)
{
QString res("0");
switch(i)
{
case 1: { res=editN1->text(); break; }
case 2: { res=editN2->text(); break; }
case 3: { res=editN3->text(); break; }
case 4: { res=editN4->text(); break; }
case 5: { res=editN5->text(); break; }
case 6: { res=editN6->text(); break; }
case 7: { res=editN7->text(); break; }
case 8: { res=editN8->text(); break; }
}
return res;
}
void threadComm::run()
{
port1= new QextSerialPort();
// init_port((editPortName->text()).unicode());
port1->setPortName(parent->getPortName());
port1->setBaudRate(BAUD9600);
port1->setDataBits(DATA_8);
port1->setFlowControl(FLOW_OFF);
port1->setParity(PAR_EVEN);
port1->setStopBits(STOP_1);
port1->setTimeout(0,100);
port1->setTextModeEnabled(FALSE);
if(port1->open(QIODevice::ReadWrite) == TRUE)qDebug("Open TRUE");
else qDebug("Open False");
port1->reset();
timer1 = new QTimer();
connect(timer1, SIGNAL(timeout()), this, SLOT(update()));
timer1->start(3000);
exec();
port1->close();
}
void threadComm::update()
{
port1->write("S98;");
port1->write("MSV?;");
QString s1("S");
QByteArray s2;
s1+=parent->getNum(1);
s1+=(";");
port1->write(s1.toAscii());
s2=port1->read(8);
parent->setValue(s2.toFloat(),0);
s1.truncate(1);
s1+=parent->getNum(2);
s1+=(";");
port1->write(s1.toAscii());
s2=port1->read(8);
parent->setValue(s2.toFloat(),1);
s1.truncate(1);
s1+=parent->getNum(3);
s1+=(";");
port1->write(s1.toAscii());
s2=port1->read(8);
parent->setValue(s2.toFloat(),2);
s1.truncate(1);
s1+=parent->getNum(4);
s1+=(";");
port1->write(s1.toAscii());
s2=port1->read(8);
parent->setValue(s2.toFloat(),3);
s1.truncate(1);
s1+=parent->getNum(5);
s1+=(";");
port1->write(s1.toAscii());
s2=port1->read(8);
parent->setValue(s2.toFloat(),4);
s1.truncate(1);
s1+=parent->getNum(6);
s1+=(";");
port1->write(s1.toAscii());
s2=port1->read(8);
parent->setValue(s2.toFloat(),5);
s1.truncate(1);
s1+=parent->getNum(7);
s1+=(";");
port1->write(s1.toAscii());
s2=port1->read(8);
parent->setValue(s2.toFloat(),6);
s1.truncate(1);
s1+=parent->getNum(8);
s1+=(";");
port1->write(s1.toAscii());
s2=port1->read(8);
parent->setValue(s2.toFloat(),7);
emit updated();
}
float loadcells::lastValue(int n1)
{
return values[n1];
}
void loadcells::setValue(float i1, int n1)
{
values[n1]=clb1->clb(i1*40/1000000, n1);
// qDebug("loadcell 1 %f" ,values[n1]);
}
//void threadComm::stop()
//{
// qDebug("Stop signal");
// exit(0);
//}
//#include <termios.h>
//#include <stdio.h>
//#include <string.h>
//#include <unistd.h>
//#include <fcntl.h>
//#include <errno.h>
//#include <pthread.h>
//#include <stdlib.h>
#define _TTY_POSIX_
#include <QDialog>
#include <QLineEdit>
#include <QLabel>
#include <QGridLayout>
#include <QPushButton>
#include <QShowEvent>
#include <QSettings>
#include <QCheckBox>
#include <QTimer>
#include <QThread>
#include "qextserialport/qextserialport.h"
#include "c16c.h"
//int init_port (char*);
//void close_port (void);
//int req_ans (u_int8_t*);
//extern int port_fd;
//extern u_int8_t msg1 [100];
//int rx (u_int8_t*, u_int8_t, u_int8_t*, int*, u_int8_t*, u_int8_t*);
//void create_msg (u_int8_t*, u_int8_t);
//void add_cs_msg (u_int8_t*);
//void add_data_msg (u_int8_t*, void*, u_int8_t);
//int tx_msg (u_int8_t*, int);
class loadcells;
class threadComm : public QThread
{
Q_OBJECT
public:
threadComm(loadcells *);
public slots:
void startC();
void stopC();
private slots:
void update();
signals:
void started();
void stopped();
void updated();
protected:
void run();
private:
QTimer *timer1;
QextSerialPort *port1;
loadcells *parent;
void update1(int);
};
class loadcells : public QDialog
{
Q_OBJECT
public:
loadcells(clbDialog*);
QString getNum(int);
float lastValue(int); //After calibration
void setValue(float, int);
// int lastError(); //0 - No error, 1...8 - no answer from loadsell 1..8, 9 - error opening serial port;
QString getPortName();
private slots:
void saveSettings();
void loadSettings();
void updatedP();
// void update();
// void commStart();
// void commStop();
signals:
// void tcStop();
void started();
void stopped();
void updated();
// void updated();
// void error();
private:
QLineEdit *editPortName;
QLineEdit *editN1;
QLineEdit *editN2;
QLineEdit *editN3;
QLineEdit *editN4;
QLineEdit *editN5;
QLineEdit *editN6;
QLineEdit *editN7;
QLineEdit *editN8;
QLabel *labelPortName;
QLabel *labelNN;
QLabel *labelP1;
QLabel *labelP2;
QLabel *labelN1;
QLabel *labelN2;
QLabel *labelN3;
QLabel *labelN4;
QLabel *labelN5;
QLabel *labelN6;
QLabel *labelN7;
QLabel *labelN8;
QGridLayout *layout1;
QPushButton *buttonStart;
QPushButton *buttonStop;
QPushButton *buttonSave;
QPushButton *buttonClose;
QCheckBox *checkAutostart;
threadComm *tc1;
QextSerialPort *port1;
clbDialog *clb1;
float values[8];
};
Reply to: