I try to get serial communication working, but struggle at waiting for the response. The logic should be to send data, wait for a response, get the response and then repeat.
To speed up my code and preventing it from blocking other independent parts of the code I run the serial communication in a separate thread.
The problem is in the send function, where I always get a "Timeout" message instead of an "Success" message.
serial.h
#ifndef SERIAL_H
#define SERIAL_H
#include <QThread>
#include <QDebug>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QStringList>
class Serial : public QThread
{
Q_OBJECT
public:
Serial();
bool send(QString text);
bool connectSerial();
void disconnectSerial();
signals:
void dataReceived(QByteArray receivedData);
protected:
void run();
private slots:
void onGetData();
private:
void readAngles();
QSerialPort qsp;
QSerialPortInfo qspi;
QByteArray receivedData;
};
#endif // SERIAL_H
serial.cpp
#include "serial.h"
Serial::Serial()
{
connect(&qsp, SIGNAL(readyRead()), this, SLOT(onGetData()));
}
bool Serial::send(QString text)
{
if (qsp.isWritable()) {
QByteArray buffer = text.toLatin1();
if (buffer.size() != qsp.write(buffer))
qDebug() << "Send does not work";
qsp.flush();
if(!qsp.waitForReadyRead(2500)) {
qDebug() << "Timeout";
} else {
qDebug() << "Success";
}
return true;
} else {
return false;
}
}
void Serial::onGetData()
{
qDebug() << "onGetData called";
qDebug() << qsp.readAll();
}
bool Serial::connectSerial(int port)
{
qDebug() << qspi.availablePorts().count();
for(int i=0; i<qspi.availablePorts().count(); i++) {
qDebug() << qspi.availablePorts().at(i).description();
}
qsp.setPort(qspi.availablePorts().at(port));
qsp.setBaudRate(QSerialPort::Baud9600);
qsp.setDataBits(QSerialPort::Data7);
qsp.setFlowControl(QSerialPort::NoFlowControl);
qsp.setParity(QSerialPort::NoParity);
qsp.setStopBits(QSerialPort::OneStop);
return qsp.open(QIODevice::ReadWrite);
}
/**
* #brief Disconnecting from serial port.
*/
void Serial::disconnectSerial()
{
if (qsp.isOpen()) {
qsp.close();
}
}
void Serial::readAngles()
{
send("012345");
}
Related
How are you solving signals/slots mechanism between two classes, if you do not make an object from class(only inherit from class) etc? QTimer, QSerialPort, which is the source of SIGNAL, and in the second class you make connection?
Is such an approach even possible?
In my case. I have two classes usb2can_driver and canview. The usb2can_driver inherit from QSerialPort, which inherit QIODevice contained SIGNAL(readyRead()). This is used in the canview for connection with handler subroutine read_u2c()
I know, in the code is a lot of garbage from testing.
In the canview.cpp void CANview::on_connectPort_released() is made connection, and in the usb2can_driver.cpp int USB2CAN_driver::connectToPort(QString portName) is part of inherit from QSerialPort.
I will be pleasure for every answer. If you think, that question is posed incorrectly, please give me feedback.
usb2can_driver.h
#ifndef USB2CAN_DRIVER_H
#define USB2CAN_DRIVER_H
#include "QSerialPort"
#include "QTimer"
#include "QObject"
#include "QSignalSpy"
class USB2CAN_driver : public QSerialPort
{
Q_OBJECT;
public:
USB2CAN_driver();
//virtual ~USB2CAN_driver();
//QSerialPort *port_USB2CAN = new QSerialPort();
int temporary_init_Counter = 0;
int init();
void USB_LoopBack();
void Boot_Mode();
void Config_Mode();
void Normal_Mode();
void LoopBack_Mode();
QByteArray Get_Mode();
void WriteReg(QByteArray regAdress, QByteArray value[]);
QByteArray WriteCMD(QByteArray CMD_name, QByteArray value);
QByteArray ReadReg(QByteArray regAdress);
QString portName;
int connectToPort(QString portName);
int disconnectedFromPort();
QTimer *tim;
int tim_counter = 0;
public: signals:
void readyRead();
private slots:
QByteArray read_USB2CAN();
void initSend();
//void timEvent();
};
#endif // USB2CAN_DRIVER_H
usb2can_driver.cpp
#include "USB2CAN_define.h"
#include "QSerialPort"
#include "QSerialPort"
#include "QObject"
#include "QDebug"
#include <QSignalSpy>
USB2CAN_driver::USB2CAN_driver()
{
//USB2CAN_driver:: = new QSerialPort();
//USB2CAN_driver::Baud9600;
//USB2CAN_driver::AllDirections;
//qDebug() << "Open port" << USB2CAN_driver::open(QIODevice::ReadWrite);
}
/*
USB2CAN_driver::~USB2CAN_driver(){
QObject::disconnect(USB2CAN_driver::,SIGNAL(readyRead()),USB2CAN_driver::,SLOT(QByteArray read_USB2CAN()));
}
*/
int USB2CAN_driver::connectToPort(QString portName){
//port_USB2CAN.setPortName(portName);
USB2CAN_driver::setPortName(portName);
USB2CAN_driver::setBaudRate(QSerialPort::Baud9600,QSerialPort::AllDirections);
USB2CAN_driver::setPortName(portName);
//Reimplemented separately as signal of driver. !!!
//qDebug() << "connect S&S in the driver, status: " << QObject::connect(this,SIGNAL(readyRead),this,SLOT(read_USB2CAN));
//qDebug() << "connect S&S in the driver, status: " << connect(this,SIGNAL(readyRead()),this,SLOT(read_USB2CAN()));
//QSignalSpy spy(this, SIGNAL(readyRead()));
//qDebug() << "from driver" << spy.wait(5000) << "----" << spy.signal();
tim = new QTimer;
return USB2CAN_driver::open(QIODevice::ReadWrite);
}
/*
void USB2CAN_driver::timEvent(){
qDebug() << "Tim" << tim_counter++;
if(tim_counter >= 5){
tim_counter = 0;
tim->stop();
}
}
*/
int USB2CAN_driver::disconnectedFromPort(){
//QObject::disconnect(this,SIGNAL(readyRead()),this,SLOT(read_USB2CAN()));
USB2CAN_driver::close();
if(USB2CAN_driver::isOpen()){
return 1;
}
else{
qDebug() << "------------------Port is diconected-----------------";
return 0;
}
}
void USB2CAN_driver::USB_LoopBack(){
}
void USB2CAN_driver::Boot_Mode(){
}
void USB2CAN_driver::Config_Mode(){
}
void USB2CAN_driver::Normal_Mode(){
}
void USB2CAN_driver::LoopBack_Mode(){
}
QByteArray USB2CAN_driver::Get_Mode(){
while(!USB2CAN_driver::waitForBytesWritten(300)){
USB2CAN_driver::write(getMode);
}
return USB2CAN_driver::readAll(); //In progress...
}
void USB2CAN_driver::WriteReg(QByteArray regAdress, QByteArray value[]){
int length = regAdress.length() + value->length();
QByteArray len;
len.setNum(length);
QByteArray sendVal[] = { writeReg, len, regAdress, *value };
QByteArray sendData;
sendData.fromRawData(*sendVal,sizeof (sendVal));
while(!USB2CAN_driver::waitForBytesWritten(300)){
USB2CAN_driver::write(sendData);
}
}
QByteArray USB2CAN_driver::WriteCMD(QByteArray CMD_name, QByteArray value){
}
QByteArray USB2CAN_driver::ReadReg(QByteArray regAdress){
}
int USB2CAN_driver::init(){
}
QByteArray USB2CAN_driver::read_USB2CAN(){
qDebug() <<"From driver RX" << USB2CAN_driver::readAll();
return USB2CAN_driver::readAll();
}
void USB2CAN_driver::initSend(){
}
canview.h
#define CANVIEW_H
#include <QDialog>
#include <usb2can_driver.h>
namespace Ui {
class CANview;
}
class CANview : public QDialog
{
Q_OBJECT
public:
explicit CANview(QWidget *parent = nullptr);
~CANview();
USB2CAN_driver *u2c;
QTimer *time;
private: signals:
friend void USB2CAN_driver::readyRead();
private slots:
void on_connectPort_released();
void on_pushButton_released();
QByteArray read_u2c();
void timerSubrutine();
private:
Ui::CANview *ui;
};
#endif // CANVIEW_H
canview.cpp
#include "ui_canview.h"
#include "QSignalSpy"
CANview::CANview(QWidget *parent) : QDialog(parent),ui(new Ui::CANview)
{
ui->setupUi(this);
u2c = new USB2CAN_driver;
}
CANview::~CANview()
{
delete ui;
}
//connect fcn
void CANview::on_connectPort_released()
{
if(u2c->isOpen()){
u2c->disconnectedFromPort();
}
else{
u2c->connectToPort(ui->inputNamePort->text());
qDebug() << "Connect rx task, status: " << connect(???,SIGNAL(readyRead()),this,SLOT(read_u2c()));
connect(u2c->tim,SIGNAL(timeout()),this,SLOT(timerSubrutine()));
u2c->tim->start(800);
}
//Controll of opened/close port
if(u2c->isOpen()){
ui->connectPort->setCheckState(Qt::CheckState::Checked);
}
else{
ui->connectPort->setCheckState(Qt::CheckState::Unchecked);
}
}
//Send function
void CANview::on_pushButton_released()
{
u2c->write(ui->TX_textBrowser->toPlainText().toLatin1(),static_cast<int>(ui->TX_textBrowser->toPlainText().length()));
qDebug() << "Send: " << static_cast<int> (ui->TX_textBrowser->toPlainText().length());
QSignalSpy spy(u2c,SIGNAL(readyRead()));
qDebug() << spy.signal() << spy.signalsBlocked() << spy.isValid();
}
QByteArray CANview::read_u2c(){
qDebug() << "RX:" << u2c->readAll();
ui->RX_textBrowser_2->setPlainText(u2c->readAll());
return u2c->readAll();
}
void CANview::timerSubrutine(){
qDebug() << "TimerEvent" << u2c->tim_counter++;
if(u2c->tim_counter >= 5){
u2c->tim->stop();
}
}```
It is impossible to connect classes as mentioned by #Scheff's Cat.
The solution is do not use inheritance from QSerialPort in the usb2can_driver. If I want connect signal of QSerialPort with slot (which is part of second class), I had to create a object from QSerialPort in the constructor of USB2CAN_driver.
This object to allow use signal/slot mechanism.
So in short: USB2CAN_driver:: was replaced by object port_USB2CAN
For the connection in the second class (canview), i used this syntax:
connect(u2c->port_USB2CAN,SIGNAL(readyRead()),this,SLOT(read_u2c()));
Thank to Scheff's Cat, your comment was helpfully. This solution is working, but if somebody see the non-standard syntax please warning me.
I'm learning about using QFtp.
I'd like to connect to a remote ftp server and list its content.
This what I wrote so far:
// libftp.cpp
#include "libftp.h"
libFTP::libFTP(QObject *parent) :
QObject(parent)
{
}
void libFTP::open(QString host)
{
connect(&ftp,SIGNAL(commandFinished(int,bool)),this,SLOT(status(int,bool)));
connect(&ftp,SIGNAL(listInfo(QUrlInfo)),this,SLOT(dir(QUrlInfo)));
ftp.setTransferMode(QFtp::Active);
ftp.connectToHost(host);
ftp.list();
ftp.cd("USER");
}
void libFTP::disconnect()
{
ftp.abort();
ftp.deleteLater();
}
void libFTP::download(QString filename)
{
ftp.get(filename);
}
void libFTP::upload(QString path,QString filename)
{
QString fullpath=path+filename;
try
{
QFile *f= new QFile(fullpath);
if(f->exists())
{
qDebug()<<"File Trovato";
ftp.mkdir("test");
//ftp.put(f,filename);
f->close();
f->deleteLater();
}
}
catch(std::exception x)
{
qDebug()<<"Errore " << x.what();
}
}
void libFTP::status(int id,bool error)
{
if(error)
{
qDebug()<<"Errore";
}
else
qDebug()<<"Status ID " << QString(id);
}
void libFTP::dir(QUrlInfo directory)
{
qDebug()<<directory.name();
}
// libftp.h
#ifndef LIBFTP_H
#define LIBFTP_H
#include <QObject>
#include <QtCore>
#include <QFtp>
#include <QUrlInfo>
class libFTP : public QObject
{
Q_OBJECT
public:
explicit libFTP(QObject *parent = 0);
void open(QString host);
void disconnect();
void download(QString filename);
void upload(QString path,QString filename);
private:
QFtp ftp;
signals:
public slots:
void status(int id,bool error);
void dir(QUrlInfo directory);
};
#endif // LIBFTP_H
And I call it from main:
#include <libftp.h>
int main()
{
libFTP *ftp = new libFTP();
ftp->open("10.20.xx.xxx");
ftp->deleteLater();
}
The server I'm connecting to accepts anonymous login.
When I try to debug this code, I notice that no slots are called and I don't see any FTP packets in my wireshark capture. In every example code I saw that's the way QFtp is used, what am I missing?
Found the issue, that wasn't immediate for a qt newbie, it didn't show any info.
I had to run QFtp in a QApplication. I think this is needed by the event loop
calling QApplication in main() solved it.
I am working on a mqtt project using QT. The publisher works fine which opens and closes a lock controlled by an raspi3, but I also need to subscribe a topic and need to start another action when the subscribed topic responses. I did a first small example as well, before starting to implement it in the bigger project which worked there fine.
But not in this project. Am I missing something?
Here are the relevant snippets from my code:
HMIController.cpp
QmlMqttClient *HMIController::createClient()
{
mqttClient = new QmlMqttClient;
mqttClient->handleSub();
return mqttClient;
}
qmlmqttclient.h
#ifndef QMLMQTTCLIENT_H
#define QMLMQTTCLIENT_H
#include <QtCore/QMap>
#include <QtMqtt/QMqttClient>
#include <QtMqtt/QMqttSubscription>
#include <QtMqtt/QMqttMessage>
class QmlMqttClient;
class QmlMqttClient : public QMqttClient
{
Q_OBJECT
public:
QmlMqttClient(QObject *parent = nullptr);
QMqttSubscription *QmlMqttClient::subscribe(const QMqttTopicFilter &topic, quint8 qos = 0);
Q_INVOKABLE qint32 publish(const QMqttTopicName &topic, const QByteArray &message = QByteArray(),
quint8 qos = 0, bool retain = false);
public slots:
void handleOpen();
void handleClose();
void handleSub();
private:
Q_DISABLE_COPY(QmlMqttClient)
private slots:
void brokerDisconnected();
};
#endif // QMLMQTTCLIENT_H
qmlmqttclient.cpp
#include <QtMqtt/QMqttSubscription>
#include <QtMqtt/QMqttTopicFilter>
#include <QMqttTopicName>
#include <QtMqtt/QMqttClient>
#include <QMqttClient>
#include <QMqttSubscription>
#include <QDateTime>
#include <QDebug>
#include <QtQuick>
#include "qmlmqttclient.h"
#include "hmicontroller.h"
QmlMqttClient::QmlMqttClient( QObject *parent)
: QMqttClient(parent)
{
this->setHostname("192.168.137.82");
this->setPort(1883);
this->connectToHost();
if (ClientState::Disconnected)
{
connect(this, &QmlMqttClient::disconnected, this, &QmlMqttClient::brokerDisconnected);
qDebug() << "Broker disconnected";
} else if (ClientState::Connecting)
{
qDebug() << "Connecting to MqttBroker ..." << this->clientId();
}
connect(this, &QMqttClient::messageReceived, this, [this](const QByteArray &message, const QMqttTopicName &topic) {
qDebug() << QDateTime::currentDateTime().toString()
+ QLatin1String(" Received Topic: ")
+ topic.name()
+ QLatin1String(" Message: ")
+ message
+ QLatin1Char('\n');
});
}
qint32 QmlMqttClient::publish(const QMqttTopicName &topic, const QByteArray &message,
quint8 qos, bool retain)
{
return QMqttClient::publish(topic, message, qos, retain);
}
void QmlMqttClient::handleOpen()
{
QString msg = "AUF";
const QMqttTopicName *topic = new QMqttTopicName("lock");
publish(*topic, msg.toUtf8() ,0);
}
void QmlMqttClient::handleClose()
{
QString msg = "ZU";
const QMqttTopicName *topic = new QMqttTopicName("lock");
publish(*topic, msg.toUtf8() ,0);
}
QMqttSubscription *QmlMqttClient::subscribe(const QMqttTopicFilter &topic, quint8 qos)
{
qDebug() << "Subscribed" << this->clientId();
return QMqttClient::subscribe(topic, qos);
}
//Called from hmicontroller
void QmlMqttClient::handleSub()
{
const QMqttTopicFilter *topic = new QMqttTopicFilter("button");
subscribe(*topic, quint8(0));
qDebug() << "Subscribed";
}
void QmlMqttClient::brokerDisconnected()
{
qDebug() << "Session closed";
}
Thanks a lot for your help and by the way, I am also new to c++ and qt. So excuse any not so nice written code.
So, I found my problem. The subscriber didn't subscribe to my specified topic, because of loading this method to fast. With a delay it works fine now.
I'm trying to send some data over serial port using QSerialPort class. Sending data from the same parent class every time works well. But when I'm trying to send data using another thread QSerialPort it doesn't. I used serial port monitor to watch the data and it showed nothing.
Code is looks like this:
#include <QSerialPort>
#include <QObject>
#include <QDebug>
#include <QCoreApplication>
#include <thread>
#include <mutex>
#include <list>
#include <memory>
class Message {
public:
bool isSent;
bool isProcessed;
int data;
Message(int d) :
data(d),
isSent(false),
isProcessed(false) {
}
};
class SerialClass : public QObject {
Q_OBJECT
public:
SerialClass(unsigned short portNumber, unsigned int baudrate, QObject *parent = 0) :
_portNumber(portNumber),
_baudrate(baudrate),
_serialPort(new QSerialPort(this)),
_messages(),
_writeThread(nullptr),
QObject(parent) {
_serialPort->setPortName(QString("COM%1").arg(_portNumber));
_serialPort->setBaudRate(baudrate);
_serialPort->setDataBits(QSerialPort::DataBits::Data8);
_serialPort->setParity(QSerialPort::Parity::NoParity);
_serialPort->setStopBits(QSerialPort::StopBits::OneStop);
}
void start() {
if (!_serialPort->open(QIODevice::ReadWrite)) {
qDebug() << "Couldn't open serial port";
return;
}
auto *m = &_messages;
auto *p = &_enableProcessing;
auto *port = _serialPort.get();
auto *mutex = &_mutex;
_serialPort->write(QString("Hello\r\n").toLocal8Bit());
_writeThread = std::make_unique<std::thread>([m, p, port, mutex]() {
qDebug() << "Work thread started";
while (*p) {
std::this_thread::sleep_for(std::chrono::milliseconds(15));
auto inactiveMessage = std::find_if(m->begin(), m->end(), [](Message &item) {
return !item.isSent;
});
if (inactiveMessage != m->end()) {
mutex->lock();
qDebug() << "Written" << port->write(QString("data %1\r\n").arg(inactiveMessage->data).toLocal8Bit());
inactiveMessage->isSent = true;
mutex->unlock();
}
}
qDebug() << "Work thread stopped";
});
}
void wait() {
if (!_writeThread) {
return;
}
_writeThread->join();
}
void addMessage(Message& msg) {
_mutex.lock();
_messages.push_back(msg);
_mutex.unlock();
}
private:
unsigned short _portNumber;
unsigned int _baudrate;
std::unique_ptr<QSerialPort> _serialPort;
std::unique_ptr<std::thread> _writeThread;
std::list<Message> _messages;
bool _enableProcessing;
std::mutex _mutex;
};
int main(int argc, char ** argv) {
QCoreApplication application(argc, argv);
SerialClass serialProcessor(2, 9600, &application);
serialProcessor.addMessage(Message(228));
serialProcessor.addMessage(Message(929));
serialProcessor.addMessage(Message(221424));
serialProcessor.start();
return application.exec();
}
#include "main.moc"
Does it means what the QSerialPort class can not transmit data from another thread? (not QSerialPort thread)
It is recommended not to mix STL and Qt solutions in the same project
QSerialPort can work in any thread
You can see an example of correct using of QThread here: https://stackoverflow.com/a/35673612/4149835
I want to write a console chat program in qt framework.I have a problem with sending messages.
Client sends messages to server but server doesn't take the messages until client program is closed.When client is closed, server displays all messages.I don't want that.I want server to get my messages when i send to it.
I wrote the codes below.You will see what i want to do if you look at main function of client.
/*
Created BY :
Creation DATE : 26/10/2012
Client interface
*/
#ifndef CLIENT_H
#define CLIENT_H
#include <QtNetwork>
#include <QObject>
#include <QtNetwork/QTcpSocket>
namespace NetworkArdic
{
class Client : public QObject
{
Q_OBJECT
public:
Client(QObject * obj = 0,QString add="localhost", quint16 port = 4000);
void SendData(QString data);
virtual ~Client();
private slots:
void ReadData();
void connected();
private:
QTcpSocket *socket;
};
}
#endif
/*
Created BY :
Creation DATE : 26/10/2012
Client source file
*/
#include "Client.h"
#include <QHostAddress>
#include <iostream>
using namespace std;
namespace NetworkArdic{
Client::Client(QObject * obj, QString add, quint16 port) : QObject(obj)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(ReadData()));
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
socket->connectToHost(QHostAddress(add), port);
}
Client::~Client(){
socket->close();
delete socket;
}
void Client::SendData(QString data)
{
if(!data.isEmpty())
{
socket->write(QString(data + "\n").toUtf8());
}
}
void Client::ReadData()
{
while(socket->canReadLine())
{
QString line = QString::fromUtf8(socket->readLine()).trimmed();
qDebug() << line;
}
}
void Client::connected()
{
socket->write(QString("Client : Server connection has been made (: \n").toUtf8());
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Client cli(0,"127.0.0.1",4000);
string line;
while(line!="exit"){
cout << "Message : ";
cin >> line;
cli.SendData(QString(line.c_str()));
}
return a.exec();
}
/*
Created BY :
Creation DATE : 26/10/2012
Server interface
*/
#ifndef SERVER_H
#define SERVER_H
#include <QtNetwork>
#include <QObject>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
namespace NetworkArdic
{
class Server: public QTcpServer
{
Q_OBJECT
public:
Server(QObject * parent = 0 , quint16 port = 4000);
virtual ~Server();
private slots:
void acceptConnection();
void startRead();
void disconnected();
private:
QTcpSocket * client;
};
}
#endif // SERVER_H
/*
Created BY :
Creation DATE : 26/10/2012
Server source file
*/
#include "Server.h"
#include <iostream>
using namespace std;
namespace NetworkArdic{
Server::Server(QObject* parent , quint16 port): QTcpServer(parent)
{
connect(this, SIGNAL(newConnection()),this, SLOT(acceptConnection()));
listen(QHostAddress::Any, port );
}
Server::~Server()
{
delete client;
close();
}
void Server::acceptConnection()
{
client = nextPendingConnection();
connect(client, SIGNAL(readyRead()), this, SLOT(startRead()));
connect(client, SIGNAL(disconnected()), this, SLOT(disconnected()));
qDebug() << "New client from:" << client->peerAddress().toString();
}
void Server::startRead()
{
while(client->canReadLine())
{
QString line = QString::fromUtf8(client->readLine()).trimmed();
qDebug() << "Client :" << line;
client->write(QString("Server : I've taken your message (:\n").toUtf8());
}
}
void Server::disconnected()
{
qDebug() << "Client disconnected:" << client->peerAddress().toString();
client->write(QString("Server : I wish you didn't leave ):\n").toUtf8());
}
}
Try using socket->flush() after you write the data.
http://doc.qt.digia.com/qt/qabstractsocket.html#flush
You used the code below to read socket data.
void Server::startRead()
{
while(client->canReadLine())
{
QString line = QString::fromUtf8(client->readLine()).trimmed();
qDebug() << "Client :" << line;
client->write(QString("Server : I've taken your message (:\n").toUtf8());
}
}
I suggest to adopt from the following code which I have tested works
while (tcp_server->hasPendingConnections()) {
client = tcp_server->nextPendingConnection();
client->waitForReadyRead(100);
QByteArray byteArray = client->readAll();
QString s_data = byteArray.data();
// Process s_data
client->close();
client->abort();
}