I wrote a C++ program in Qt that used dynamic memory allocation, and I made sure to include the free() call at the end. However, when the program reaches the free statement, it crashes. (I know this because the test that I added never printed after the free statements) Anyway, here's the code:
#include <QCoreApplication>
#include <QSerialPort>
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <Windows.h>
using namespace std;
int main(int argc, char *argv[])
{
QSerialPort serial0;
//serial.open(serial);
serial0.setBaudRate(QSerialPort::Baud9600);
serial0.setDataBits(QSerialPort::Data8);
serial0.setParity(QSerialPort::NoParity);
serial0.setStopBits(QSerialPort::OneStop);
serial0.setFlowControl(QSerialPort::NoFlowControl);
char *com="com";
int number;
char *comPlusNumber;
comPlusNumber=(char*) malloc(8*sizeof(char));
int j=10000;
while(j>0)
{
number=j;
sprintf(comPlusNumber, "%s%d",com,number);
//printf("%s \n",comPlusNumber);
serial0.setPortName(comPlusNumber);
serial0.open(QIODevice::ReadWrite);
if(serial0.isOpen()==true)
{
printf("YES*****************");
printf("%s \n",comPlusNumber);
}
else
//printf("No %d\n", number);
serial0.close();
j--;
}
free(com);
free(comPlusNumber);
printf("\n\n Test");
//QCoreApplication a(argc, argv);
//return a.exec();
}
I just wanted to make sure that I wasn't creating a memory leak.
Use the framework. You've got the power of Qt!
There are several problems:
The C-style string manipulations are unnecessary and wrong. Use QString:
auto name = QStringLiteral("COM%1").arg(i);
You can't use the serial port without a QCoreApplication instance present.
You shouldn't be testing for the presence of a port by iterating what you think might be valid ports. This is non-portable and unnecessary. Get a list of ports to start with.
Thus:
// https://github.com/KubaO/stackoverflown/tree/master/questions/simple-serial-35181906
#include <QtCore>
#include <QtSerialPort>
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
QSerialPort serial;
serial.setBaudRate(QSerialPort::Baud9600);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);
serial.setFlowControl(QSerialPort::NoFlowControl);
for (auto port : QSerialPortInfo::availablePorts()) {
serial.setPort(port);
serial.open(QIODevice::ReadWrite);
if (serial.isOpen()) {
qDebug() << "port" << port.portName() << "is open";
serial.close();
} else
qDebug() << "port" << port.portName() << "couldn't be opened";
}
}
Here's the output on my machine:
port "cu.serial1" is open
port "cu.usbserial-FTELA9I5" is open
port "cu.usbserial-PX9A3C3B" is open
You can only free what you dynamically allocated. You never dynamically allocated anything for com, so passing it to free is an error. It's equivalent to free("com"); which attempts to free a string constant.
Related
I am learning C++ with Qt. I have installed Qt 5.15 and am using VS2019. I have the below code (as per an example in a textbook I am working through):
#include <QtGui>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTextStream cout(stdout);
//declarations of variables
int answer = 0;
do{
//local variables
int factArg = 0;
int fact(1);
factArg = QInputDialog::getInt(0, "Factorial Calculator", "Factorial of:", 1);
cout << "User entered: " << factArg << endl;
int i = 2;
while (i <= factArg) {
fact = fact * i;
++i;
}
QString response = QString("The factorial of %1 is %2.\n%3").arg(factArg).arg(fact).arg("Do you want to compute another factorial?");
answer = QMessageBox::question(0, "Play again?", response, QMessageBox::Yes | QMessageBox::No);
} while (answer == QMessageBox::Yes);
return EXIT_SUCCESS;
}
However, I am recieving the below error when creating an instance of QApplication as app:
Incomplete Type is not Allowed
I am also recieving the below error for the QInputDialog and QMessageBox classes:
name followed by '::' must be a class or namespace name
I am not sure why this is happening - presumably something with a namespace, but I am not sure what scope to provide. I have searched the web but to no avail.
UPDATE
Adding the below header references give cannot open source file error for each.
#include <QApplication>
#include <QInputDialog>
#include <QMessageBox>
I have also added suggestions from the comments to my code, now below:
#include <QtGui>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTextStream cout(stdout);
//declarations of variables
int answer = 0;
do{
//local variables
int factArg = 0;
int fact(1);
factArg = QInputDialog::getInt(0, "Factorial Calculator", "Factorial of:", 1);
cout << "User entered: " << factArg << endl;
int i = 2;
while (i <= factArg) {
fact = fact * i;
++i;
}
QString response = QString("The factorial of %1 is %2.\n%3").arg(factArg).arg(fact).arg("Do you want to compute another factorial?");
answer = QMessageBox::question(0, "Play again?", response, QMessageBox::Yes | QMessageBox::No);
} while (answer == QMessageBox::Yes);
return EXIT_SUCCESS;
}
But I am still recieving the same errors.
You have to include some qt headers in the app... that is the meaning of the message
you just need to add this to your code
#include <QApplication>
#include <QInputDialog>
#include <QMessageBox>
The correct headers to include are the following:
#include <QtWidgets/QApplication>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMessageBox>
Once declaring these, the compiler accepts the code.
I'm going to cut and paste a working program for you.
Qt seems to have a bunch of forward definitions. I can tell I'm missing the right include file if I try to get the IDE to actually help me select a method call. In short, you pretty much have to #include every widget type or other class you're going to use. I haven't run into any shortcuts.
#include <QApplication>
#include "MainWindow.h"
using namespace std;
/**
* Main entry point.
*/
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
I am trying to transfer data from Arduino to a C++ Qt5.7 and from a Arduino to a C++ Qt5.7 (MinGW) program.
I am able to transfer the data FROM QT TO ARDUINO without any problems.
The Arduino blinks perfectly.
On the other hand, the data transfered FROM THE ARDUINO TO QT isnt always the expected (sends "LED ON" when it should be "LED OFF") and sometimes it doesnt communicate at all!
QT code:
#include <QCoreApplication>
#include <QDebug>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QThread>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSerialPort serial;
serial.setPortName("COM6");
serial.setBaudRate(9600);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);
serial.setFlowControl(QSerialPort::NoFlowControl);
if(serial.open(QSerialPort::ReadWrite))
{
string c;
QByteArray s;
QByteArray received;
while(true)
{
qDebug("TRUE");
//WRITE
cin >> c;
cout << endl;
s = QByteArray::fromStdString(c);
serial.write(s);
serial.waitForBytesWritten(-1);
//serial.flush();
s = serial.readAll();
serial.waitForReadyRead(-1);
cout << s.toStdString() << endl;
//serial.flush();
}
}
else
{
QString error = serial.errorString();
cout << error.toStdString() << endl;
qDebug("FALSE") ;
}
serial.close();
return a.exec();
}
The ARDUINO CODE:
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
}
// the loop function runs over and over again forever
void loop() {
delay(1000); // wait for a second
}
void serialEvent()
{
char inChar;
while (Serial.available())
{
// get the new byte:
inChar = (char)Serial.read();
if(inChar == 'a')
{
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
}
else
{
digitalWrite(LED_BUILTIN, LOW); // turn the LED off (LOW is the voltage level)
}
}
delay(500);
if(inChar == 'a')
{
Serial.write("LED ON");
}
else
{
Serial.write("LED OFF");
}
}
Terminal Image of Error:
TERMINAL WITH ERROR image
Please help!
Thank you,
You have no packetization whatsoever: there are no delimiters between individual chunks of data - other than time passing.
On the Arudino side, instead of write, you should use println so that each message is a complete line.
On the Qt side, process complete lines. You're not guaranteed to get a complete response from the serial port after waitForReadyRead. All that you're guaranteed is that at least 1 byte is available to read. That is the source of your problem. Note how you got LE, then sometime later you got D OFF immediately followed by LED ON. You must wait for data until complete line(s) are available.
The following should work on the Qt end of things - also note that you don't need as many includes, and you can use QTextStream instead of iostream, to lower the number of APIs that you use. Finally, you don't need app.exec since you write blocking code.
// https://github.com/KubaO/stackoverflown/tree/master/questions/arduino-read-40246601
#include <QtSerialPort>
#include <cstdio>
int main(int argc, char *argv[])
{
QCoreApplication a{argc, argv};
QTextStream in{stdin};
QTextStream out{stdout};
QSerialPort port;
port.setPortName("COM6");
port.setBaudRate(9600);
port.setDataBits(QSerialPort::Data8);
port.setParity(QSerialPort::NoParity);
port.setStopBits(QSerialPort::OneStop);
port.setFlowControl(QSerialPort::NoFlowControl);
if (!port.open(QSerialPort::ReadWrite)) {
out << "Error opening serial port: " << port.errorString() << endl;
return 1;
}
while(true)
{
out << "> ";
auto cmd = in.readLine().toLatin1();
if (cmd.length() < 1)
continue;
port.write(cmd);
while (!port.canReadLine())
port.waitForReadyRead(-1);
while (port.canReadLine())
out << "< " << port.readLine(); // lines are already terminated
}
}
If you wish, you can also easily turn it into a GUI application, it's only a few lines to do so:
#include <QtSerialPort>
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication app{argc, argv};
QWidget ui;
QFormLayout layout{&ui};
QLineEdit portName{"COM6"};
QTextBrowser term;
QLineEdit command;
QPushButton open{"Open"};
layout.addRow("Port", &portName);
layout.addRow(&term);
layout.addRow("Command:", &command);
layout.addRow(&open);
ui.show();
QSerialPort port;
port.setBaudRate(9600);
port.setDataBits(QSerialPort::Data8);
port.setParity(QSerialPort::NoParity);
port.setStopBits(QSerialPort::OneStop);
port.setFlowControl(QSerialPort::NoFlowControl);
QObject::connect(&open, &QPushButton::clicked, &port, [&]{
port.setPortName(portName.text());
if (port.open(QSerialPort::ReadWrite)) return;
term.append(QStringLiteral("* Error opening serial port: %1").arg(port.errorString()));
});
QObject::connect(&command, &QLineEdit::returnPressed, &port, [&]{
term.append(QStringLiteral("> %1").arg(command.text()));
port.write(command.text().toLatin1());
});
QObject::connect(&port, &QIODevice::readyRead, &term, [&]{
if (!port.canReadLine()) return;
while (port.canReadLine())
term.append(QStringLiteral("< %1").arg(QString::fromLatin1(port.readLine())));
});
return app.exec();
}
I think you must use EOL and Carrige return character on QT. Try to replace Serial.write to Serial.println in Arduino code.
I am trying to implement GUI for a simple C++ using Qt to understand how it works. The C++ program and the GUI are in seperate projects in the same solution in VS 2015. The Qt program will call the C++ program using QProcess' start() function. The C++ console application will be running the background will the Qt program acts as an interface. My question is, how I do I pass values to the C++ program using QProcess and How do I obtain the output from the C++ program? Here is the sample program I am working with:-
The C++ Program
#include<iostream>
#include<fstream>
using namespace std;
void main() {
int a;
cout << "Enter a number" << endl;
cin >> a;
cout << "The Square of the number is " << (a*a) << endl;
ofstream write;
write.open("test.txt");
write << (a * a);
write.close();
}
The Qt Program
#include "FrontEnd.h"
#include <QtWidgets/QApplication>
#include <qprocess.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FrontEnd w;
w.show();
QProcess p1;
p1.start("Interface.exe");
p1.write("5",5);
return a.exec();
}
I tried to pass the value using the write() function but it did not seem to work as the test.txt file remained empty. The Qt program I have written lacks the GUI features as I will be adding them once I figure out how to send and recieve data using QProcess. Thank you for your assistance!
You have many problems in the code you are showing:
You are passing write two arguments "5" and 5, this means that it will use 5 chars from the the char* "5". Absolutely, this is not what you want as this will lead to undefined behavior resulted from accessing memory that does not belong to your data.
Instead you should be using the second version of write which accepts a zero-terminated string, like this: p1.write("5");
In order to make cin in your console program know that the number it should read is finished, you should pass a new line after your number, so your call will end up like this: p1.write("5\n");
You should use the readyRead signal in the Qt program to get notified when your process has new output that you can read, and then you may call readAll from a slot which is connected to that signal.
For completeness, Here is how your code should be:
interface.cpp
#include<iostream>
using namespace std;
void main() {
int a;
cin >> a;
//No need to use file output
//it is simpler and more appropriate to read the output from stdout
cout << "The Square of the number is " << (a*a) << endl;
}
The Qt program
#include <QApplication>
#include <QWidget>
#include <QProcess>
#include <QDebug>
#include "FrontEnd.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FrontEnd w;
w.show();
QProcess p1;
p1.start("Interface.exe");
p1.write("5\n");
QObject::connect(&p1, &QProcess::readyRead, [&p1](){
//output to qDebug, you may want to update some GUI component instead
qDebug() << p1.readAll();
});
return a.exec();
}
With this code
#include "mainwindow.h"
#include <QApplication>
#include <iostream>
#include <QDir>
#include <QTextStream>
int main(int argc, char *argv[]){
QApplication a(argc, argv);
QTextStream out(stdout);
out << QDir::currentPath();
std::cout << "Why is that?";
MainWindow mainWindow;
mainWindow.show();
return a.exec();
}
Both messages printed only after closing Main Window of my app, why is this?
I tried to debug, debugger thinks that he done with this line, but I see no messages.
extern std::ostream cout; is buffered, so it may choose when to flush its buffer to stdout. In your case, it is doing it when your program is terminating.
You can tell std::ostream to flush using std::flush, as such:
std::cout << "Why is that?" << std::flush;
I am trying to rig up some basic serial communications in QT
I am getting the port COM19 from QSerialPortInfo, and I speaking successfully to the port via Arduino. However, I cannot get anything back via QT.
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QTextStream>
#include <QFile>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){
qDebug() << "Name :" << info.portName();
qDebug() << "Description :" << info.description();
qDebug() << "Manufactuer :" << info.manufacturer();
QSerialPort serial;
serial.setPort(info);
if(serial.open(QIODevice::ReadWrite))
qDebug() << serial.errorString();
serial.write("M114 \n");
qDebug() << serial.readAll();
serial.close();
// Now we need to send and receive commands
serial.setPortName("COM19");
serial.setBaudRate(QSerialPort::Baud57600);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);
serial.setFlowControl(QSerialPort::NoFlowControl);
if(serial.open(QIODevice::ReadWrite)){
qDebug() << "opened";
}else{
qDebug() << "Not opened";
}
qDebug() << serial.errorString();
serial.write("M114 \n");
qDebug() << serial.readAll();
serial.close();
}
MainWindow w;
w.show();
return a.exec();
}
As you can see, I am trying a simple connection along the lines of the documentation, and one where I write out all the baud rate information. They throw two different errors.
Like I said, I am connecting via arduino to this same port and having success. Any ideas what's wrong?
Name : "COM19"
Description : "USB Serial (Communication Class, Abstract Control Model)"
Manufactuer : "PJRC.COM, LLC."
"Unknown error"
""
opened
"The handle is invalid."
""
Any ideas for what I am doing wrong?
My idea is to send commands to the device, and read them back to the console.
the code looks a bit confuse. You open all port available and then you try to do something wrong.
NOTE: You use a GUI application like a shell application. It is wrong.
Try:
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QTextStream>
#include <QFile>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSerialPort serial;
serial.setPortName("COM19");
if(serial.open(QIODevice::ReadWrite)){
//Now the serial port is open try to set configuration
if(!serial.setBaudRate(QSerialPort::Baud57600))
qDebug()<<serial.errorString();
if(!serial.setDataBits(QSerialPort::Data8))
qDebug()<<serial.errorString();
if(!serial.setParity(QSerialPort::NoParity))
qDebug()<<serial.errorString();
if(!serial.setStopBits(QSerialPort::OneStop))
qDebug()<<serial.errorString();
if(!serial.setFlowControl(QSerialPort::NoFlowControl))
qDebug()<<serial.errorString();
//If any error was returned the serial il corrctly configured
serial.write("M114 \n");
//the serial must remain opened
if(serial.waitForReadyRead(100)){
//Data was returned
qDebug()<<"Response: "<<serial.readAll();
}else{
//No data
qDebug()<<"Time out";
}
//I have finish alla operation
serial.close();
}else{
qDebug()<<"Serial COM19 not opened. Error: "<<serial.errorString();
}
MainWindow w;
w.show();
return a.exec();
}
Starting with the tenth port, his name will be \\.\COM10
You can reassign the port to a different number in Device Manager