text append waits until hcitoo scan is finished
-
I expect each hcitool system call to update textEdit , but it does not occur
until hcitool scan is finished.
I like to time some of the system hcitool calls and it appears that it won't be that simple if this cannot be resolved.
I am open to suggestions.
Thanksvoid Form::on_pushButton_2_clicked() { // QString *tempFileName = {"log_file.txt"}; // freopen( tempFileName , "w"); //, (FILE*)1); QString FileName = "log_file.txt"; ui->textEdit_2->append(" TRACE initialized"); system("hcitool"); //>> log_file.txt); ui->textEdit_2->append(" TRACE hcitool dev"); system("hcitool dev" ); ui->textEdit_2->append(" TRACE hcitool inq"); system("hcitool inq " ); ui->textEdit_2->append(" TRACE hcitool scan"); system("hcitool scan " ); #ifdef BYPASS #endif }
-
The UI is not updated until the program returns to the Qt event loop; which is after this function exits.
You could output timestamps into your text edit before/after each call. They'll all appear when the function exits.
You could use the time Linux/UNIX command to timehcitool
outside of the Qt program (and capture that output).
You could use the Qt provided Bluetooth functionality instead. -
I expect each hcitool system call to update textEdit , but it does not occur
until hcitool scan is finished.
I like to time some of the system hcitool calls and it appears that it won't be that simple if this cannot be resolved.
I am open to suggestions.
Thanksvoid Form::on_pushButton_2_clicked() { // QString *tempFileName = {"log_file.txt"}; // freopen( tempFileName , "w"); //, (FILE*)1); QString FileName = "log_file.txt"; ui->textEdit_2->append(" TRACE initialized"); system("hcitool"); //>> log_file.txt); ui->textEdit_2->append(" TRACE hcitool dev"); system("hcitool dev" ); ui->textEdit_2->append(" TRACE hcitool inq"); system("hcitool inq " ); ui->textEdit_2->append(" TRACE hcitool scan"); system("hcitool scan " ); #ifdef BYPASS #endif }
-
-
@ChrisW67As always, you are correct.
So I found this example and it is sort of working.
When I first run it I got "file not found" error - which was expected.
(I think if I run this function only once , in push button event , I wdillw get the file erro back
Now I have two problems - still getting the error BUT no longer includes the "file is missing message" . Then the hcitoll won't terminate and that gives another error.Printing the standard error..........
QProcess: Destroyed while process ("hcitool") is still running.
Form::ProcessCommand(QString command ). So I am not sure why hcotool won't terminate, but I think it is the dunction which won't finish the error message.
Because it works just fine , without getting the full error when call the to function single.
I really do not need to call all the commands in sequence as I am testin in now.So I'll work on the error.
BTW
How do I pass an empty "argument list ?
.timer.start();
// ProcessCommand("hcitool", {" "}); no arg list - does not work
// ProcessCommand("hcitool",{ " "});
ProcessCommand("hcitool",{ "dev"});
ProcessCommand("hcitool", {"inq"});
ProcessCommand("hcitool", {"scan "});Here is the current , UNDER CONSTRUCTION, version of the usage of QProcess
int Form::ProcessCommand(QString Command, QStringList args ) { qDebug("Form::ProcessCommand(QString command ) "); std::cout<<"\n * Program to demonstrate the usage of linux commands in qt * \n"; timer.elapsed(); QString s = QString::number(timer.elapsed()); s = "ProcessCommand START elapsed time " + s; ui->textEdit_2->append(s); QProcess OProcess; // QString Command; //Contains the command to be executed // QStringList args; //Contains arguments of the command // Command = "ls"; // args<<"-l"<<"/home/anil"; OProcess.start(Command,args,QIODevice::ReadWrite); //Starts execution of command //QProcess.start(Command,) OProcess.waitForFinished(); //Waits for execution to complete QString StdOut = OProcess.readAllStandardOutput(); //Reads standard output QString StdError = OProcess.readAllStandardError(); //Reads standard error std::cout<<"\n Printing the standard output..........\n"; std::cout<<std::endl<<StdOut.toStdString(); std::cout<<"\n Printing the standard error..........\n"; std::cout<<std::endl<<StdError.toStdString(); std::cout<<"\n\n"; s = QString::number(timer.elapsed()); s = "ProcessCommand END elapsed time " + s; ui->textEdit_2->append(s); //system(Command.toStdString().c_str()); //>> log_file.txt); return 0; };
-
Using QProcess that way is more or less the same as calling system since you are blocking the event loop.
-
My last post is little screwed-up.
The error text is always executed and reason I do no have a real error - I did not add the "redirect " to file yet.Which is subject of this post
-
what exactly is QIODevice as coded in an example ?
-
QIODevice::Append append to file - so where in the "start" I add the file ?
This adds file data to arg . Is that correct ?
//Process.Start("cmd.exe", "/c foo.exe -arg >" + dumpDir + "\foo_arg.txt"); -
How can I option to execute BOTH
QIODevice::ReadWrite & QIODevice::Append)
this did not work
-
-
Using QProcess that way is more or less the same as calling system since you are blocking the event loop.
@SGaist Good point, but it does not matter in my application. I am more concerned why I cannot run the function consecutively.
Cheers -
- it's the base class of QProcess
- No it's not, at best it will overwrite the file. If you want to append to a file in a shell you need to use >>
- You want to execute your process, then read the output it generated though QProcess API and then use a QFile to write what you want to the file. QProcess is not a full shell so the redirection that you try to use won't work.
-
- it's the base class of QProcess
- No it's not, at best it will overwrite the file. If you want to append to a file in a shell you need to use >>
- You want to execute your process, then read the output it generated though QProcess API and then use a QFile to write what you want to the file. QProcess is not a full shell so the redirection that you try to use won't work.
@SGaist It works as expected when I add the file redirection in "arg".
I am back to need refresh course on "HCI".
My process function is timing out because there is no response from "hcitool".
I am really frustrated with this Bluetooth stuff - how low do I have to go to get it working / responding reliably and in time. I believe there is a spec somewhere to tell how long before the HCI commands timeout.I have no issue with local "dev" but it is the "scan" or "inq" which is killing the process .
-
The blocking behaviour of
hcitool
is not a Qt problem.hcitool
has options for controlling timeouts (at least the Bluez source code I am looking at does). However, you seem to be running something on Windows, so I have no idea what yourhcittool
really is.Is there a reason that you are not using the Qt Bluetooth support?
-
I am also facing some kind of erroneous things which I am sharing along with btconnect.h file -
This is my btconnect.h file#ifndef BTCONNECT_H
#define BTCONNECT_H#include "scandialog.h"
namespace Ui {
class BTConnect;
}class BTConnect : public QWidget
{
Q_OBJECTpublic:
explicit BTConnect(QWidget *parent = 0);
~BTConnect();private slots:
void on_ScanButton_clicked();void ScanBTDevices(); //some slots here void ScanDialogShow(); void ScanDialogClose();
public slots:
//some slots hereprivate:
Ui::BTConnect *ui;QProcess BTscan_Process; scanDialog *scan;
};
#endif // BTCONNECT_H
btconnect.cppBTConnect::BTConnect(QWidget *parent) :
QWidget(parent),
ui(new Ui::BTConnect)
{
//set the userinterface as BTConnect.ui
ui->setupUi(this);scan = new scanDialog(this);
}
void BTConnect::ScanDialogShow()
{
scan->show();
}void BTConnect::ScanDialogClose()
{
scan->close();
}void BTConnect::ScanBTDevices()
{
ScanDialogShow();//Command to scan nearby bluetooth devices //"hcitool scan" QString cmd("hcitool scan"); //start the process BTscan_Process.start(cmd); //Wait for the processs to finish with a timeout of 20 seconds if(BTscan_Process.waitForFinished(20000)) { //Clear the list widget this->ui->listWidget->clear(); //Read the command line output and store it in QString out QString out(BTscan_Process.readAllStandardOutput()); //Split the QString every new line and save theve in a QStringList QStringList OutSplit = out.split("\n"); //Parse the QStringList in btCellsParser btCellsParser cp(OutSplit); for(unsigned int i = 0; i<cp.count(); i++) { //writing in listwidget } } ScanDialogClose();
}
void BTConnect::on_ScanButton_clicked()
{
//Scan for available nearby bluetooth devices
ScanBTDevices();
}
if I use the above code, the qdialog scandialog does open when the process begins and closes when the data is loaded in qlistwidget, but the contents of qdialog scandialog are not displayed. If I were to change show() to exec(), the contents will be shown but the QProcess does not run until the dialog is closed.I want the dialog to open when the Qprocess starts and close when the qlistwidget is loaded with data from the scan. And I want the contents of scandialog to be displayed. It has two labels. One with .GIF file and another with text saying scanning.
Any help is appreciated.
Answer - 1
0 arrow_circle_up 0 arrow_circle_down
The problem is that QDialog::exec and QProcess::waitForFinished functions block event loop. Never ever block event loop. So you just need to do things more asynchronously.QProcess class can be handled asynchronously using signals like readReadStandardOutput. And QDialog can be shown asynchronously using open slot.
The example:
void ScanBTDevices() {
// Open dialog when process is started
connect(process, SIGNAL(started()), dialog, SLOT(open()));// Read standard output asynchronously connect(process, SIGNAL(readyReadStandardOutput()), SLOT(onReadyRead())); // Start process asynchronously (for example I use recursive ls) process->start("ls -R /");
}
void onReadyRead() {
// Write to list widget
dialog->appendText(QString(process->readAllStandardOutput()));
}
The data will be appended to the dialog during generating by process. Also using QProcess::finished signal and you can close the dialog.by *
Answer - 2 verified
0 arrow_circle_up 0 arrow_circle_down
you never return to the event loop when you do show (because of waitForFinished) and you never continue to the processing code when you do execinstead of the waitForFinished you should connect to the finished signal and handle it there and use a single shot timer that will cancel it:
void BTConnect::on_BTscanFinished()//new slot
{
//Clear the list widget
this->ui->listWidget->clear();//Read the command line output and store it in QString out QString out(BTscan_Process.readAllStandardOutput());
After doing all of this I basically stuck on virtual onboarding software.
//Split the QString every new line and save theve in a QStringList
QStringList OutSplit = out.split("\n");//Parse the QStringList in btCellsParser btCellsParser cp(OutSplit); for(unsigned int i = 0; i<cp.count(); i++) { //writing in listwidget } ScanDialogClose();
}
void BTConnect::ScanBTDevices()
{
ScanDialogShow();//Command to scan nearby bluetooth devices //"hcitool scan" QString cmd("hcitool scan"); //start the process connect(BTscan_Process, SIGNAL(finished()), this, SLOT(on_BTscanFinished())); BTscan_Process.start(cmd); QTimer::singleShot(20000, scan, SLOT(close()));
}
Hope this will properly help you.
-
I am also facing some kind of erroneous things which I am sharing along with btconnect.h file -
This is my btconnect.h file#ifndef BTCONNECT_H
#define BTCONNECT_H#include "scandialog.h"
namespace Ui {
class BTConnect;
}class BTConnect : public QWidget
{
Q_OBJECTpublic:
explicit BTConnect(QWidget *parent = 0);
~BTConnect();private slots:
void on_ScanButton_clicked();void ScanBTDevices(); //some slots here void ScanDialogShow(); void ScanDialogClose();
public slots:
//some slots hereprivate:
Ui::BTConnect *ui;QProcess BTscan_Process; scanDialog *scan;
};
#endif // BTCONNECT_H
btconnect.cppBTConnect::BTConnect(QWidget *parent) :
QWidget(parent),
ui(new Ui::BTConnect)
{
//set the userinterface as BTConnect.ui
ui->setupUi(this);scan = new scanDialog(this);
}
void BTConnect::ScanDialogShow()
{
scan->show();
}void BTConnect::ScanDialogClose()
{
scan->close();
}void BTConnect::ScanBTDevices()
{
ScanDialogShow();//Command to scan nearby bluetooth devices //"hcitool scan" QString cmd("hcitool scan"); //start the process BTscan_Process.start(cmd); //Wait for the processs to finish with a timeout of 20 seconds if(BTscan_Process.waitForFinished(20000)) { //Clear the list widget this->ui->listWidget->clear(); //Read the command line output and store it in QString out QString out(BTscan_Process.readAllStandardOutput()); //Split the QString every new line and save theve in a QStringList QStringList OutSplit = out.split("\n"); //Parse the QStringList in btCellsParser btCellsParser cp(OutSplit); for(unsigned int i = 0; i<cp.count(); i++) { //writing in listwidget } } ScanDialogClose();
}
void BTConnect::on_ScanButton_clicked()
{
//Scan for available nearby bluetooth devices
ScanBTDevices();
}
if I use the above code, the qdialog scandialog does open when the process begins and closes when the data is loaded in qlistwidget, but the contents of qdialog scandialog are not displayed. If I were to change show() to exec(), the contents will be shown but the QProcess does not run until the dialog is closed.I want the dialog to open when the Qprocess starts and close when the qlistwidget is loaded with data from the scan. And I want the contents of scandialog to be displayed. It has two labels. One with .GIF file and another with text saying scanning.
Any help is appreciated.
Answer - 1
0 arrow_circle_up 0 arrow_circle_down
The problem is that QDialog::exec and QProcess::waitForFinished functions block event loop. Never ever block event loop. So you just need to do things more asynchronously.QProcess class can be handled asynchronously using signals like readReadStandardOutput. And QDialog can be shown asynchronously using open slot.
The example:
void ScanBTDevices() {
// Open dialog when process is started
connect(process, SIGNAL(started()), dialog, SLOT(open()));// Read standard output asynchronously connect(process, SIGNAL(readyReadStandardOutput()), SLOT(onReadyRead())); // Start process asynchronously (for example I use recursive ls) process->start("ls -R /");
}
void onReadyRead() {
// Write to list widget
dialog->appendText(QString(process->readAllStandardOutput()));
}
The data will be appended to the dialog during generating by process. Also using QProcess::finished signal and you can close the dialog.by *
Answer - 2 verified
0 arrow_circle_up 0 arrow_circle_down
you never return to the event loop when you do show (because of waitForFinished) and you never continue to the processing code when you do execinstead of the waitForFinished you should connect to the finished signal and handle it there and use a single shot timer that will cancel it:
void BTConnect::on_BTscanFinished()//new slot
{
//Clear the list widget
this->ui->listWidget->clear();//Read the command line output and store it in QString out QString out(BTscan_Process.readAllStandardOutput());
After doing all of this I basically stuck on virtual onboarding software.
//Split the QString every new line and save theve in a QStringList
QStringList OutSplit = out.split("\n");//Parse the QStringList in btCellsParser btCellsParser cp(OutSplit); for(unsigned int i = 0; i<cp.count(); i++) { //writing in listwidget } ScanDialogClose();
}
void BTConnect::ScanBTDevices()
{
ScanDialogShow();//Command to scan nearby bluetooth devices //"hcitool scan" QString cmd("hcitool scan"); //start the process connect(BTscan_Process, SIGNAL(finished()), this, SLOT(on_BTscanFinished())); BTscan_Process.start(cmd); QTimer::singleShot(20000, scan, SLOT(close()));
}
Hope this will properly help you.
@Jamieghosal Many thanks for the post. I am glad I found somebody who does "Bluetooth" coding.
Your post is a big help, however at this time I have to fix "updating" QT.
The example function is OK , but it still keep QT from updating until it is finished. I need to work on that first.Speaking of Bluetooth - I am very often experiencing a total "screw-up" - even using commands running terminal won't work. The only "solution" is to switch / reboot to another OS _ I am, running multi-boot - all Ubuntu.
I really believe "bluez" is the worst application and it is "part of the Linux kernel" - hence I am trying to bypass it using HCI directly.
-
The blocking behaviour of
hcitool
is not a Qt problem.hcitool
has options for controlling timeouts (at least the Bluez source code I am looking at does). However, you seem to be running something on Windows, so I have no idea what yourhcittool
really is.Is there a reason that you are not using the Qt Bluetooth support?
@ChrisW67 Yes, QTBluetooth "support" won't even recognize that I turned Bluetooth off in OS - and happily reports "finished " - no error.
I did try at lest two versions of QTCreator with same result.
FYI _ I am using Ubuntu. -
I am also facing some kind of erroneous things which I am sharing along with btconnect.h file -
This is my btconnect.h file#ifndef BTCONNECT_H
#define BTCONNECT_H#include "scandialog.h"
namespace Ui {
class BTConnect;
}class BTConnect : public QWidget
{
Q_OBJECTpublic:
explicit BTConnect(QWidget *parent = 0);
~BTConnect();private slots:
void on_ScanButton_clicked();void ScanBTDevices(); //some slots here void ScanDialogShow(); void ScanDialogClose();
public slots:
//some slots hereprivate:
Ui::BTConnect *ui;QProcess BTscan_Process; scanDialog *scan;
};
#endif // BTCONNECT_H
btconnect.cppBTConnect::BTConnect(QWidget *parent) :
QWidget(parent),
ui(new Ui::BTConnect)
{
//set the userinterface as BTConnect.ui
ui->setupUi(this);scan = new scanDialog(this);
}
void BTConnect::ScanDialogShow()
{
scan->show();
}void BTConnect::ScanDialogClose()
{
scan->close();
}void BTConnect::ScanBTDevices()
{
ScanDialogShow();//Command to scan nearby bluetooth devices //"hcitool scan" QString cmd("hcitool scan"); //start the process BTscan_Process.start(cmd); //Wait for the processs to finish with a timeout of 20 seconds if(BTscan_Process.waitForFinished(20000)) { //Clear the list widget this->ui->listWidget->clear(); //Read the command line output and store it in QString out QString out(BTscan_Process.readAllStandardOutput()); //Split the QString every new line and save theve in a QStringList QStringList OutSplit = out.split("\n"); //Parse the QStringList in btCellsParser btCellsParser cp(OutSplit); for(unsigned int i = 0; i<cp.count(); i++) { //writing in listwidget } } ScanDialogClose();
}
void BTConnect::on_ScanButton_clicked()
{
//Scan for available nearby bluetooth devices
ScanBTDevices();
}
if I use the above code, the qdialog scandialog does open when the process begins and closes when the data is loaded in qlistwidget, but the contents of qdialog scandialog are not displayed. If I were to change show() to exec(), the contents will be shown but the QProcess does not run until the dialog is closed.I want the dialog to open when the Qprocess starts and close when the qlistwidget is loaded with data from the scan. And I want the contents of scandialog to be displayed. It has two labels. One with .GIF file and another with text saying scanning.
Any help is appreciated.
Answer - 1
0 arrow_circle_up 0 arrow_circle_down
The problem is that QDialog::exec and QProcess::waitForFinished functions block event loop. Never ever block event loop. So you just need to do things more asynchronously.QProcess class can be handled asynchronously using signals like readReadStandardOutput. And QDialog can be shown asynchronously using open slot.
The example:
void ScanBTDevices() {
// Open dialog when process is started
connect(process, SIGNAL(started()), dialog, SLOT(open()));// Read standard output asynchronously connect(process, SIGNAL(readyReadStandardOutput()), SLOT(onReadyRead())); // Start process asynchronously (for example I use recursive ls) process->start("ls -R /");
}
void onReadyRead() {
// Write to list widget
dialog->appendText(QString(process->readAllStandardOutput()));
}
The data will be appended to the dialog during generating by process. Also using QProcess::finished signal and you can close the dialog.by *
Answer - 2 verified
0 arrow_circle_up 0 arrow_circle_down
you never return to the event loop when you do show (because of waitForFinished) and you never continue to the processing code when you do execinstead of the waitForFinished you should connect to the finished signal and handle it there and use a single shot timer that will cancel it:
void BTConnect::on_BTscanFinished()//new slot
{
//Clear the list widget
this->ui->listWidget->clear();//Read the command line output and store it in QString out QString out(BTscan_Process.readAllStandardOutput());
After doing all of this I basically stuck on virtual onboarding software.
//Split the QString every new line and save theve in a QStringList
QStringList OutSplit = out.split("\n");//Parse the QStringList in btCellsParser btCellsParser cp(OutSplit); for(unsigned int i = 0; i<cp.count(); i++) { //writing in listwidget } ScanDialogClose();
}
void BTConnect::ScanBTDevices()
{
ScanDialogShow();//Command to scan nearby bluetooth devices //"hcitool scan" QString cmd("hcitool scan"); //start the process connect(BTscan_Process, SIGNAL(finished()), this, SLOT(on_BTscanFinished())); BTscan_Process.start(cmd); QTimer::singleShot(20000, scan, SLOT(close()));
}
Hope this will properly help you.
@Jamieghosal I think the basic "problem" is
OProcess.waitForFinished(60000);
I do not get how QT executes basic C function by "waiting" for it to return "true".
That basically blocks the rest of the code and I expect "process" not to do that.
So it back to finding out how to make "process" NOT to block the rest of the code. Long time ago I used QProgressBar and it is the time to try it again - I should be able to "update" the QProgressBar on each second - hence the QProcess needs to be convinced to do so. -
@Jamieghosal I think the basic "problem" is
OProcess.waitForFinished(60000);
I do not get how QT executes basic C function by "waiting" for it to return "true".
That basically blocks the rest of the code and I expect "process" not to do that.
So it back to finding out how to make "process" NOT to block the rest of the code. Long time ago I used QProgressBar and it is the time to try it again - I should be able to "update" the QProgressBar on each second - hence the QProcess needs to be convinced to do so.@AnneRanch QProcess is asynchronous as already explained. Learn how to use it that way.
-
@SGaist And what do you think I am doing ? I do not need such comments.
Cheers -
Well, you are using the blocking API, hence my suggestion. Stop doing that and use signals and slots to manage your QProcess object.
Make a list of the commands you want to execute. Pick the first, start it, then when it is done (use the finished signal to know), start the next on the list and so on until they are all done. No freeze will happen.
-
Well, you are using the blocking API, hence my suggestion. Stop doing that and use signals and slots to manage your QProcess object.
Make a list of the commands you want to execute. Pick the first, start it, then when it is done (use the finished signal to know), start the next on the list and so on until they are all done. No freeze will happen.
@SGaist Tep, that is what I am doing and as usual I am stuck on "connect".
Sure could use a real example of connect to get me going...
This "wait for completion" sure was of no help to really understand QProcess...