Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Send a serial message before closing the serial port in Qt



  • Hello there :)
    I'm trying to develop an user interface in Qt for an academic project, which sends serial messages to a microcontroller. I'm struggling with the closing of the serial port though: the user interface should send a serial message to the microcontroller before closing the serial port. This is the portion of the code which manages this operation:

    device->write(QString("ABORT___").toStdString().c_str());
    displayMessage("Disconnected");
    deviceIsConnected = false;
    device->close();
    ui->PortComboBox->setEnabled(true);
    ui->tabWidget->setEnabled(false);
    ui->ConnectButton->setText("Connect");
    ui->ConnectionStatus->setText("<span style=\" color:#e1d41f;\">DISCONNECTED</span>");
    

    The problem is that this code closes the port before that the message is actually sent, in fact if i try to comment this line device->close(); the code works as expected. It seems like that the port is closed before the message is sent, even if the line that manages the port closing is after. Even if i try to nest the device->close(); line in some if statements, the issue persists.
    I also tryed to use the function waitForBytesWritten() in an if statement, but the issue persists.

    Can you help me?



  • @Chicowolf

    Do you use any signals & slots?

    Wait until last message was sent and then close connection.

    Have a look at some examples
    https://doc.qt.io/qt-5/qtserialport-examples.html



  • Yeah, as was mentioned, you need to wait until the message is actually sent before closing the port. The single threaded procedural approach would be to sample the serial status in a loop directly after the write, which is shunned in Qt. The event driven approach is to track the status of the serial link, and only close the port once a signal has been received to indicate that the write is complete. How to actually do this is an exercise for the student.



  • I tryed to use the function waitForBytesWritten() like this:

            device->write(QString("DISCONCT").toStdString().c_str());
            if(device->waitForBytesWritten(30000))
            {
                displayMessage("Disconnected");
                deviceIsConnected = false;
                device->close();
                ui->PortComboBox->setEnabled(true);
                ui->tabWidget->setEnabled(false);
                ui->ConnectButton->setText("Connect");
                ui->ConnectionStatus->setText("<span style=\" color:#e1d41f;\">DISCONNECTED</span>");
            }
    

    but the issue persists. The port is well configured because the program sends other messages over serial port, and the messages are well received, except for the "DISCONCT" message.

    EDIT:
    I also tested the write line through qDebug and it returns 8


  • Lifetime Qt Champion

    Hi,

    Does that message get an acknowledge from the device ?

    On a side note, there's no need for these multiple conversions you are doing in your write call. Just call it with the string you want to send.



  • No the message is not received: the device receives 4 random character/ascii codes instead of the word "DISCONCT"

    Thanks for the suggestion :)


  • Qt Champions 2019

    Did you try QIODevice::flush()?



  • @Christian-Ehrlicher nope, how should i use it?


  • Qt Champions 2019

    @Chicowolf said in Send a serial message before closing the serial port in Qt:

    how should i use it?

    I don't understand - simply call it? QSerialPort is derived from QIODevice...



  • @Christian-Ehrlicher ok, i tryed to call it before and after the write call, but the issue persists

    Image
    this is the message received by the device: as you can see, it's a random message of 4 bytes instead of the 8 byte message i sent


  • Qt Champions 2019

    Are you using windows? Which Qt version exactly? waitForBytesWritten() + flush() should work for sure.



  • Yes, i'm using windows and Qt 5.14.1
    This is my code now

            device->flush();
            device->write(QString("DISCONCT").toStdString().c_str());
            device->flush();
            if(device->waitForBytesWritten(30000))
            {
                displayMessage("Disconnected");
                deviceIsConnected = false;
                device->close();
                ui->PortComboBox->setEnabled(true);
                ui->tabWidget->setEnabled(false);
                ui->ConnectButton->setText("Connect");
                ui->ConnectionStatus->setText("<span style=\" color:#e1d41f;\">DISCONNECTED</span>");
            }
    


  • What is your state machine for the microcontroller? What is it suppose to do when it receives "DISCONCT"? Does it expect that the command be newline terminated? Can you sample a GPIO on the microcontroller when it receives the DISCONCT? Your problem may be on the embedded component and not in the Qt logic of "send and wait"....but without seeing the controller program I don't know how you're parsing the incoming command either.



  • The state of the microcontroller is "CONNECTED" since the program sends the message "HELLO___" to the micro. When it receives "DISCONCT" it goes to "IDLE" state, ready to reconnect again if needed. It doesn't expect any '\n' character. I could use an oscilloscope, but it doesn't have the UART decoder fuction built-in; i'm monitoring the internal variables though, thanks to the debug mode in the micro, and i'm pretty sure that the issue is related to the close() call, since if i comment that call, the message is received.
    As you can see in the image i posted in the previous answer, the micro's variable "RxData" it's not filled with the "DISCONCT" word, but with 4 random character.

    To be fair, with the waitForBytesWritten(30000) call, the program doesn't seem that it waits for 30 second, it seems pretty responsive instead. If necessary i could post the entire code.


  • Qt Champions 2019

    If you're already Debugging the Qt code then make some breakpoints inside qserialport_win.cpp in the close() and waitForBytesWritten methods.



  • @Christian-Ehrlicher thank for the suggestion :)
    I made 3 breakpoints in the write(), waitForBytesWritten() and close() calls. The message is sent without problems, but after the flush() call, not after the write() call; the waitForBytesWritten(30000) call, doesn't wait for 30 seconds, but the close() call works as expectet.
    Now that i put these three breakpoints the program seems to work fine, even in non-debug mode. I don't understand what is going on :/



  • There are no any way to know that a data has been written to the physical line.

    A best way is wait for a device response (e.g. ACK) and only then close the port. Other way is just use QSP::bytesWritten() signal, and after this signal received wait a bit using QTimer with some empiric timeout (e.g. with some milliseconds), and only then close the port.



  • I'm sorry to say it, but I'm leaning toward a questionable protocol on the embedded board. You are trying to parse block commands from a stream data feed. There are oh so many potential problems by not using either 1) all fixed length commands, or 2) choosing and consistently using an end of message indicator like \n...and consistently sending a status indicator upon receipt and processing of EVERY COMMAND.


Log in to reply