How can i let a loop for reading data from embedded device usually actif
-
@dziko147 said in How can i let a loop for reading data from embedded device usually actif:
But my app crashes .
Run it in a debugger to see why it crashes. The code you show would not crash. Nobody can tell you why it might crash from this code.
If you have to continually read from the device as you show you would need to put it in a thread, to avoid blocking the UI, and communicate back to the UI thread via an emitted signal. If you can "poll" the device you may get away without a separate thread by using a
QTimer
from the UI thread instead. -
Hi
In Qt app that is event-based. For/while FOREVER running loops are a death sentence.
You strangulate your app as it won't be allowed to repaint or get mouse inputs. So Don't do it if
you have any kind of GUI you want to work at the same time.So if you cant use a QTimer then do as JonB suggests and run it in a thread.
-
@dziko147 in your other topic, that you now apparently deleted, I suggested to go away from an invite loop to a QTimer.
I think you misunderstood me if you explicitly changed to a while loop
I had something like this in mind:
class MyCanBusClass : public QObject { Q_OBJECT public: MyCanBusClass(QObject *parent = nullptr) : QObject(parent), m_fetchFrameTimer(this){ connect(&m_fetchFrameTimer, & QTimer::timeout, this, &MyCanBusClass::fetchNextDataFrame); m_fetchFrameTimer.setSingleShot(true); m_canDevice = QCanBus::instance()->createDevice(QStringLiteral("socketcan"), QStringLiteral("can0")); connect(m_canDevice, &QCanBusDevice::framesReceived, this, &MyCanBusClass::onFramesReceived); connect(m_canDevice, &QCanBusDevice::framesWritten, this, &MyCanBusClass::onFramesWritten); } signals: void signalForUiUpdate(QStringList Outputs); private slots: void onFramesReceived(){ QStringList list; // .... // .... emit signalForUiUpdate(list); } void onFramesWritten(){ m_fetchFrameTimer.start(10000); // 10000 ms } private: void fetchNextDataFrame(){ QCanBusFrame firstframetosend; } private: QCanBusDevice *m_canDevice; QTimer m_fetchFrameTimer; };
signalForUiUpdate
than connected to a slot in your UI class, to update the Ui -
@J-Hilk said in How can i let a loop for reading data from embedded device usually actif:
private slots:
void onFramesReceived(){
QStringList list;
// ....
// ....
emit signalForUiUpdate(list);
}@J-Hilk Hello :)
here what should I do ?
Just I call my variable like this .list << variable1 << variable2 ........ ;
Or I must set putt here the function which fill the data . ?
I mean this code :
for(size_t i=0;i<Inputs.size();i++){ //Envoie de la commande upload qDebug() << "Input type" << Inputs[i]; if(Inputs[i]=="double") { frameupload.setFrameId(frameId); frameupload.setPayload(payloadupload8byte); qDebug() << "type is double : upload commande is" << payloadupload8byte; device->writeFrame(frameupload); } else{ frameupload.setFrameId(frameId); frameupload.setPayload(payloadupload); qDebug() << "type is not double : upload commande is" << payloadupload; device->writeFrame(frameupload); } // fin de la commande upload device->waitForFramesReceived(3000); QCanBusFrame framereceived = device->readFrame(); // Reception 1ére données QByteArray data = QByteArray::fromHex(framereceived.payload()); qDebug() << QByteArray::fromHex(framereceived.payload()) << " Data Data&size" << QByteArray::fromHex(framereceived.payload()).size(); // QByteArray data = QByteArray::fromHex("FF42480000"); QDataStream stream(data); qDebug() << data.size() << " Data Data&size" ; if (data.size()== 5){ stream.setFloatingPointPrecision(QDataStream::SinglePrecision); }else { stream.setFloatingPointPrecision(QDataStream::DoublePrecision); } quint8 byte; stream >> byte; // skip first byte stream >> myData; // read data qDebug() << "this is data"<< myData ; QString DatatoString =QString::number(myData); Outputs[i]=DatatoString; qDebug() << "In outputs data" << Outputs[i]; //fin récuperation } m_Valuespeed=Outputs[0].toDouble(); m_ValueId=Outputs[1].toFloat(); m_ValueIQ=Outputs[2].toFloat(); m_ValueIdRef=Outputs[3].toFloat(); m_ValueIQRef=Outputs[4].toFloat(); m_ValueVD=Outputs[5].toFloat(); m_ValueVQ=Outputs[6].toFloat(); m_ValueVDRef=Outputs[7].toFloat(); m_ValueVQRef=Outputs[8].toFloat(); m_valueDCvolt=Outputs[9].toFloat(); m_ValueCPU1=Outputs[10].toFloat(); m_ValueCPU2=Outputs[11].toFloat(); m_ValueCPU3=Outputs[12].toFloat(); m_ValueCPU4=Outputs[13].toFloat(); m_ValueCPU5=Outputs[14].toFloat(); m_ValueCPU6=Outputs[15].toFloat(); m_ValueCPU7=Outputs[16].toFloat(); m_ValueCPU8=Outputs[17].toFloat(); m_ValueTorque=Outputs[18].toFloat(); m_ValueTorqueMax=Outputs[19].toFloat(); m_directiontext=Outputs[20]; m_motiontext=Outputs[21]; m_nbrevoltext=Outputs[22]; m_degradedtext=Outputs[23]; m_dischtext=Outputs[24]; }
thank you
-
well,
QStringList list
is a, substitution for yourOutputs
variablethe slot that receives the signal would than update the ui
void updateUiWithFrameData(QStringList Outputs)
{
m_Valuespeed=Outputs[0].toDouble();
m_ValueId=Outputs[1].toFloat();
m_ValueIQ=Outputs[2].toFloat();
m_ValueIdRef=Outputs[3].toFloat();
m_ValueIQRef=Outputs[4].toFloat();
m_ValueVD=Outputs[5].toFloat();
m_ValueVQ=Outputs[6].toFloat();
m_ValueVDRef=Outputs[7].toFloat();
m_ValueVQRef=Outputs[8].toFloat();
m_valueDCvolt=Outputs[9].toFloat();
m_ValueCPU1=Outputs[10].toFloat();
m_ValueCPU2=Outputs[11].toFloat();
m_ValueCPU3=Outputs[12].toFloat();
m_ValueCPU4=Outputs[13].toFloat();
m_ValueCPU5=Outputs[14].toFloat();
m_ValueCPU6=Outputs[15].toFloat();
m_ValueCPU7=Outputs[16].toFloat();
m_ValueCPU8=Outputs[17].toFloat();
m_ValueTorque=Outputs[18].toFloat();
m_ValueTorqueMax=Outputs[19].toFloat();
m_directiontext=Outputs[20];
m_motiontext=Outputs[21];
m_nbrevoltext=Outputs[22];
m_degradedtext=Outputs[23];
m_dischtext=Outputs[24];}
-
@J-Hilk So if understand .
I don't need to change my function which fill data :void Backend::statuspican() { float myDatafloat; double myDatadouble; bool ok; std::array<QString,25> Inputs{"real","double","double","double","double","double","double","double","double","double" ,"real","real","real","real","real","real","real","real","double","double","boolean","double" ,"uint32","boolean","boolean"}; QByteArray payloadupload= QByteArray::fromHex("F504"); QByteArray payloadupload8byte= QByteArray::fromHex("F508"); QByteArray Testsend= QByteArray::fromHex("FF"); // réponse static QByteArray payloadrpm= QByteArray::fromHex("F600000000180010"); // Rpm @ QString ID = "101"; const uint frameId = ID.toUInt(nullptr, 16); QCanBusFrame firstframetosend; QCanBusFrame frameupload; QCanBusDevice *device = QCanBus::instance()->createDevice( QStringLiteral("socketcan"), QStringLiteral("can0")); if(device->connectDevice()){ //changer avant la validation //Récuperation de Rpm //Envoie de l'@ Rpm firstframetosend.setFrameId(frameId); firstframetosend.setPayload(payloadrpm); device->writeFrame(firstframetosend); // fin @Rpm device->waitForFramesReceived(3000); QCanBusFrame rpmreponse= device->readFrame(); QByteArray Testreponse = rpmreponse.payload(); if(Testreponse==Testsend){ //test de la reponse for(size_t i=0;i<Inputs.size();i++){ //Envoie de la commande upload qDebug() << "Input type" << Inputs[i]; if(Inputs[i]=="double") { frameupload.setFrameId(frameId); frameupload.setPayload(payloadupload8byte); qDebug() << "type is double : upload commande is" << payloadupload8byte; device->writeFrame(frameupload); } else{ frameupload.setFrameId(frameId); frameupload.setPayload(payloadupload); qDebug() << "type is not double : upload commande is" << payloadupload; device->writeFrame(frameupload); } // fin de la commande upload device->waitForFramesReceived(3000); QCanBusFrame framereceived = device->readFrame(); // Reception 1ére données QByteArray data = framereceived.payload(); qDebug() << data<< " this is frame data" ; qDebug() << data.size() << " Data Data&size" ; if (data.size()==5){ data.remove(0,1); QByteArray byte1 =data.left(1); QByteArray byte2nonpret =data.left(2); QByteArray byte2 =byte2nonpret.right(1); QByteArray byte3nonpret =data.left(3); QByteArray byte3 =byte3nonpret.right(1); QByteArray byte4 =data.right(1); QByteArray Datareversed = byte4+byte3+byte2+byte1; QDataStream stream(Datareversed); // quint8 byte; // stream >> byte; // skip first byte stream.setFloatingPointPrecision(QDataStream::SinglePrecision); stream >> myDatafloat; // read data QString DatatoString =QString::number(myDatafloat); Outputs[i]=DatatoString; } if(data.size()==8){ data.remove(0,1); qDebug() << data << " data remove FF" ; QByteArray byte1 =data.left(1); QByteArray byte2nonpret =data.left(2); QByteArray byte2 =byte2nonpret.right(1); QByteArray byte3nonpret =data.left(3); QByteArray byte3 =byte3nonpret.right(1); QByteArray byte4nonpret =data.left(4); QByteArray byte4 =byte4nonpret.right(1); QByteArray byte0 =QByteArray::fromHex("00000000"); QByteArray Datareversed2 = byte4+byte3+byte2+byte1+byte0; qDebug() << Datareversed2<< "data 8Byte reversed" ; QDataStream stream2(Datareversed2); stream2.setFloatingPointPrecision(QDataStream::DoublePrecision); stream2 >> myDatadouble; // read data QString DatatoString =QString::number(myDatadouble); Outputs[i]=DatatoString; } /* quint8 byte; stream >> byte; // skip first byte stream >> myData; // read data qDebug() << "this is data"<< myData ; QString DatatoString =QString::number(myData); Outputs[i]=DatatoString; qDebug() << "In outputs data" << Outputs[i];*/ //fin récuperation } m_Valuespeed=Outputs[0].toFloat(&ok); m_ValueId=Outputs[1].toDouble(&ok); m_ValueIQ=Outputs[2].toDouble(&ok); m_ValueIdRef=Outputs[3].toDouble(&ok); m_ValueIQRef=Outputs[4].toDouble(&ok); m_ValueVD=Outputs[5].toDouble(&ok); m_ValueVQ=Outputs[6].toDouble(&ok); m_ValueVDRef=Outputs[7].toDouble(&ok); m_ValueVQRef=Outputs[8].toDouble(&ok); m_valueDCvolt=Outputs[9].toDouble(&ok); m_ValueCPU1=Outputs[10].toFloat(&ok); m_ValueCPU2=Outputs[11].toFloat(&ok); m_ValueCPU3=Outputs[12].toFloat(&ok); m_ValueCPU4=Outputs[13].toFloat(&ok); m_ValueCPU5=Outputs[14].toFloat(&ok); m_ValueCPU6=Outputs[15].toFloat(&ok); m_ValueCPU7=Outputs[16].toFloat(&ok); m_ValueCPU8=Outputs[17].toFloat(&ok); m_ValueTorque=Outputs[18].toDouble(&ok); m_ValueTorqueMax=Outputs[19].toDouble(&ok); m_directiontext=Outputs[20]; m_motiontext=Outputs[21]; m_nbrevoltext=Outputs[22]; m_degradedtext=Outputs[23]; m_dischtext=Outputs[24]; for (size_t k=0;k<Outputs.size() ; k++) { qDebug() << "Data after convert " << Outputs[k]; } } } }
Just I need to redefine my constructor :
Backend::Backend(QObject *parent ) :QObject(parent), m_fetchFrameTimer(this) { std::array<QString,25> Outputs; m_directiontext="null"; m_motiontext="null"; m_nbrevoltext="null"; m_degradedtext="null"; m_dischtext="null"; m_Valuespeed=0; m_ValueTorque=0; m_ValueTorqueMax=0; m_ValueCPU1=0; m_ValueCPU2=0; m_ValueCPU3=0; m_ValueCPU4=0; m_ValueCPU5=0; m_ValueCPU6=0; m_ValueCPU7=0; m_ValueCPU8=0; m_ValueId=0; m_ValueIdRef=0; m_ValueIQ=0; m_ValueIQRef=0; m_ValueVD=0; m_ValueVQ=0; m_ValueVDRef=0; m_ValueVQRef=0; m_valueDCvolt=0; }
And Add your code to Backend.h
-
@dziko147 Hey, great you made it :D
You're example was a bit to complex for me to simply restructure in a couple of lines, and I hadn't hat the time to actually tackle it.
All the better that you managed to restructure it yourself with only a few abstract tips! Kudos!
I can post my code if anyone need it
If you want to, do it, no-one is gonna judge :D but some may be grateful and some may offer tips/suggestions still :D
thank you bro :D
-
Dear Reader if you want to display simultaneously your c++ data to Qml .
you can try my solution . :DUsually we can do better but the most important things is that solution works very well :D
So :
First of all we must prepare the app design : try to use this https://doc.qt.io/qt-5/qtqml-cppintegration-topic.html .
then use a Qtimer to make a repetitive read of data.Finally , Use Setters to update your data .
Definition of Qobject class which fill and update data :
In Backend.hQTimer m_fetchFrameTimer;
Backend.cpp
Backend::Backend(QObject *parent ) :QObject(parent),m_fetchFrameTimer(new QTimer(this)) { connect(&m_fetchFrameTimer, & QTimer::timeout, this, &Backend::statuspican); m_fetchFrameTimer.start(1000); //Statuspican : function for fill data
statuspican :
void Backend::statuspican() { //Some code to fetch data setValue(yourvalue);