Qt5 QSerialPort write data - qt

How I can write data in serial port, with delay between send's messages?
This is my code:
void MainWindow::on_pushButton_Done_clicked()
{
if(sport->isOpen()){
sport->clear();
QString cmd = Phase+Mode;
//Write Stop
sport->write("stop!", 5);
//Write Mode
sport->write(cmd.toStdString().c_str(), cmd.toStdString().length());
//Write Speed
sport->write(Speed.toStdString().c_str(), Speed.toStdString().length());
//Write Direction
sport->write(Direction.toStdString().c_str(), Direction.toStdString().length());
//Run
sport->write("start!", 6);
}
}
My device receives an error message when I call this function.
Thank you.

2 options:
use waitForBytesWritten to ensure the bytes are written and then a short sleep
however this will block the thread and will block the gui
the other is using a QTimer to trigger another slot a few times and a field that will indicate what needs to be sent

Looks like you are trying to program some step motor controller or something similar.
Usually in such controllers you should wait for controller response to verify that command was processed properly.
It looks like that your design of code is very bad. Move everything related with this controller to separate class, which has set of slots, something like: starRotateLeftWithSpeed(double). Code will be cleaner and it will be easy to use thread if you decide to use methods like waitForBytesWritten proposed in another answer.
Definitely you should read controller manual more carefully.

Related

Send signal data from QMainwindow to QDialog

I am going to send data collected in the QMainWindow to an object of QDialog via signal-slot connections. Here is the relevant code fragment to do this in mainwindow.cpp:
void MainWindow::on_dialogA_clicked()
{
if(dialogA==NULL) dialogA =new MyDialog();
//'this' refers to MainWindow
connect(this,SIGNAL(sendData(QVector<bool>)), dialogA, SLOT(getData(QVector<bool>)), Qt::QueuedConnection);
dialogA->show();
}
However when working with dialogA, it seems that the data are not updated properly and the dialog interface becomes Not responding after while. I wonder if the signal-slot connection above is right or not, or that is the way to have data communication with a QDiaglog.
Two things...first, switch to the modern method of creating signal/slot connections:
connect (this, &MainWindow::sendData, dialogA, &MyDialog::getData, Qt::QueuedConnection);
If there's something wrong with the definition, using this format allows the compiler to catch it rather than a run-time warning. Assuming the parameters are defined correctly, there's nothing wrong with the "connect" statement except that it's in the wrong place, which is the second issue.
Every time the user clicks, an additional connection is being made between your main window and the dialog. Qt doesn't automatically ensure that only one connection is made between a given signal and slot. It'll create as many as you ask it for. The "connect" call should be part of the "if" block:
if (! dialogA)
{
dialogA =new MyDialog();
connect...
}
Depending on how much data is in that vector and what the dialog does with it, if you click enough times, it may be that you're just processing the data so many times that everything slows down tremendously.

QAudioRecorder detect user not speaking and stop

I want to use QAudioRecorder to record audio from the user and then use the audio output file for speech to text. I could successfully run and record audio from this example, http://doc.qt.io/qt-5/qtmultimedia-multimedia-audiorecorder-example.html.
But my problem is, I need to detect if user has stopped speaking while QAudioRecorder is actively recording audio. So QAudioRecorder should only stop when user is not speaking.
I could stop QAudioRecorder for fixed seconds using QTimer as below:
void AudioRecorder::toggleRecord()
{
if (audioRecorder->state() == QMediaRecorder::StoppedState) {
audioRecorder->setAudioInput(boxValue(ui->audioDeviceBox).toString());
QAudioEncoderSettings settings;
settings.setCodec(boxValue(ui->audioCodecBox).toString());
settings.setSampleRate(boxValue(ui->sampleRateBox).toInt());
settings.setBitRate(boxValue(ui->bitrateBox).toInt());
settings.setChannelCount(boxValue(ui->channelsBox).toInt());
settings.setQuality(QMultimedia::EncodingQuality(ui->qualitySlider->value()));
settings.setEncodingMode(ui->constantQualityRadioButton->isChecked() ?
QMultimedia::ConstantQualityEncoding :
QMultimedia::ConstantBitRateEncoding);
QString container = boxValue(ui->containerBox).toString();
audioRecorder->setEncodingSettings(settings, QVideoEncoderSettings(), container);
audioRecorder->record();
this->recordTimeout();
}
else {
this->stopRecording();
}
}
void AudioRecorder::recordTimeout()
{
QTimer* mTimer = new QTimer(this);
mTimer->setSingleShot(true);
connect(mTimer, SIGNAL(timeout()), SLOT(stopRecording()));
mTimer->start(6000);
}
void AudioRecorder::stopRecording()
{
audioRecorder->stop();
}
But instead of this it should stop recording when user is not speaking. The QAudioProbe class has this signal audioBufferProbed(QAudioBuffer) which may be helpful to check level of audio but I don't know how to use it and what level can be used to detect if user is not speaking.
I've been trying to do more or less the same thing for a while now. There is an example - https://doc.qt.io/qt-5/qtdatavisualization-audiolevels-example.html that shows you how implement an audio level meter which should be helpful. The example uses QAudioInput. Specifically, it uses QAudioInput::start(QIODevice * device) and passes a custom QIODevice to implement the audio level meter. The problem with this approach using QAudioInput is once you've got the data, it's not easy to encode it and write it out to file where as with QAudioRecorder it's simple.
Anyway ... your right QAudioProbe is your best bet if you want to record the easy way with QAudioRecorder. I adapted the Qt audio level meter example to work with QAudioProbe instead of QAudioInput/QIODevice. See - https://gist.github.com/sam-at-github/bf66e84105cc3e23e7113cca5e3b1772.
One minor issue the level meter needs QAudioFormat but QAudioRecorder only provides you with a QEncoderSettings (Should probably fix code to use the latter. I don't know why both QEncoderSettings and QAudioFormat need to exist ...). You just gotta get a QAudioDeviceInfo for the device your using then use QAudioDeviceInfo::preferredFormat().
Relaed Post: Qt: API to write raw QAudioInput data to file just like QAudioRecorder

How to disconnect a signal with a slot temporarily in Qt?

I connect a slot with a signal. But now I want to disconnect them temporarily.
Here is part of my class declaration:
class frmMain : public QWidget
{
...
private:
QTimer *myReadTimer;
...
private slots:
void on_btnDownload_clicked();
...
};
In the constructor of frmMain, I connect myReadTimer with a slot so that ReadMyCom will be called every 5 seconds:
myReadTimer=new QTimer(this);
myReadTimer->setInterval(5000);
connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
But, in slot on_btnDownload_clicked. I don't want myReadTimer to emit any signal in on_btnDownload_clicked's scope. So I want to disconnect them at the beginning of on_btnDownload_clicked and reconnect them in the end. Like this:
void frmMain::on_btnDownload_clicked()
{
//some method to disconnect the slot & singal
...//the code that I want myReadTimer to leave me alone
//some method to reconnect the slot & singal
}
I searched in Stackoverflow and got some answer like call the QObject destructor. But I don't know how to use it.
I also tried to use disconnect, like:
QMetaObject::Connection myConnect;
myConnect=connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
...
disconnect(& myConnect);
But it still not work. So could any one help me how to do this?
There is a very nice function in QObject that comes in handy every now and again: QObject::blockSignals()
Here's a very simple fire-and-forget class that will do what you want. I take no credit for it's design, I found it on the internet somewhere a long time ago. Be careful though, it will block all signals to all objects. If this is not what you want, you can modify the class to suit your needs.
class SignalBlocker{
public:
SignalBlocker(QObject *o): object(o), alreadyBlocked(object->signalsBlocked()){
if (!alreadyBlocked){
object->blockSignals(true);
}
}
~SignalBlocker() {
if (!alreadyBlocked){
object->blockSignals(false);
}
}
private:
QObject *object;
bool alreadyBlocked;
};
Usage, in your case, becomes trivial
void frmMain::on_btnDownload_clicked()
{
SignalBlocker timerSignalBlocker(myReadTimer);
...//the code that I want myReadTimer to leave me alone
// signals automatically unblocked when the function exits
}
UPDATE:
I see that from Qt 5.3, a very similar class has been offically added to the API. It does a similar job as the one above with a slightly bigger feature-set. I suggest you use the official QSignalBlocker class instead in order to keep your codebase up-to-date with any API changes.
Usage, however, remains exactly the same.
Disconnect/reconnect syntax
There are many ways to call disconnect, depending on exactly what you want disconnected. See the QObject documentation page for an explanation of how they work.
Here's an example using 0 to mean "disconnect all slots."
void frmMain::on_btnDownload_clicked()
{
// disconnect everything connected to myReadTimer's timeout
disconnect(myReadTimer, SIGNAL(timeout()), 0, 0);
...//the code that I want myReadTimer to leave me alone
// restore the connection
connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
}
Or you can specify the exact signal-slot pair to disconnect by copying your 'connect' syntax, like this:
disconnect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
Stopping the timer
Since you're working with a timer, this may be simpler:
void frmMain::on_btnDownload_clicked()
{
// stop the timer (so you won't get any timeout signals)
myReadTimer->stop();
...//the code that I want myReadTimer to leave me alone
// restart the timer (using whatever interval was set previously)
myReadTimer->start();
}
Differences from your original approach:
Since you're stopping and restarting the timer, the next time it fires will be interval after your slot function finishes.
Do you need to do anything special at all?
In a single-threaded Qt application, if you're already handling a signal, another signal won't "jump in the middle" of that code. Instead it'll be queued up as an even to handle immediately after the current slot returns.
So perhaps you don't need to stop or disconnect your timer at all.
Differences from your original approach:
If on_btnDownload_clicked takes a while to execute, you might have multiple ReadMyCom events queued up after on_btnDownload_clicked completes. (Note that at this point you'd have an operation that basically "locks up" your GUI for a while anyway; it may make more sense to refactor the function or give it its own thread.)

Handling COM serial port communication

I was thinking about a best approach to properly handle the serial port communication in my program. I have some device that sends me data, im reciving it using DataRecieved event and ReadExisting method in it. Everything that it reads is being put inside a buffer, when last line equals some string then i start to parse it into some kind of packet.
Aside from that, when i send data to this device and wait for response, i mark flag
bool isReady = false;
while(!isReady)
Thread.Sleep(500);
And in data parsing method i set this flag to true so when I recieve packet data, code can jump out of this loop and continue to work as needed. But in my opinion this is not a clean/good way to do this. And there is a problem sometimes, if device will not send the packet I need, so program is being stuck in the loop forever.
I was wondering, how would you guys resolve this case in your code?
Thanks, and sorry for bad english.
Don't just wait for a response in an endless loop. Use the events like you previously mentioned to get the data. See this other SO question also. SerialPort class and DataReceived event... Getting bytes. Use ReadLine or ReadExisting? Any examples?
For now i've added a 5sec timeout using following code:
bool isReady = false;
DateTime timeout = DateTime.Now;
while(!isReady)
{
Thread.Sleep(500);
if((DateTime.Now-timeout).TotalMiliseconds >= 5000)
break;
}
So when no response is recieved then it just jumps out of this loop. This is solving one of my problems, but still I would like to know other ways to handle this. If you guys have any ideas, please share them.

reading from console without pausing the program

i have made a small opengl program using the d programming language. what i am trying to do is to allow the program to read input from the console. i have tried to use readf(), getc() and some other functions. but my problem is i don't want the program to pause while looking for input.
i have tried to search around for a solution but could not find any. so if anyone know how to check if something actually have been written in the console and if so read that. or if there exists any function that reads from console, but will be ignored if nothing gets written.
i mainly would like to know how to do this in d but a solution for c++ could be useful too.
You need to use a separate thread. Something like this is one way to do it in D:
import std.stdio, std.concurrency;
void main()
{
// Spawn a reader thread to do non-blocking reading.
auto reader = spawn(()
{
// Read console input (blocking).
auto str = readln();
// Receive the main thread's TID and reply with the string we read.
receive((Tid main) { send(main, str); });
});
// ... This is where you can do work while the other thread waits for console input ...
// Let the reader thread know the main thread's TID so it can respond.
send(reader, thisTid);
// Receive back the input string.
receive((string str) { writeln("Got string: ", str); });
}
This spawns a separate thread which does the console input waiting while your main thread can do other work.

Resources