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

QUdpSocket multicast receiver timeout detection?



  • I am using multicast receiver example. How can I add a timer where if I loose the multicast signal and don't get any multicast signal in a specific time, then it will set a gpio to high?
    This is what I tried but it does not work the way its supposed to.

    if (udpSocket->hasPendingDatagrams() != 1)
    {
    QTimer::singleShot(5000, this, SLOT(nomsg()));
    }
    
    
    void MainWindow::nomsg()
    {
    ::gpio_set_value(this->GREEN_LED_PIN, HIGH);
    }
    
    

    I receive 1 udp signal every second, so this program just keeps toggling the gpio to high and low.
    I just want to turn my gpio high if I don't get any multicast message in 5 seconds.

    Any help will be greatly appreciated.



  • @samy03
    You need to be reading the datagrams that do arrive, e.g. via QUdpSocket::receiveDatagram().

    How about:

    1. Create function to set GREEN (nomsg()).
    2. Create function to set off QTimer::singleShot(5000, this, SLOT(nomsg()));.
    3. Set off that function initially.
    4. In readyRead slot whenever a datagram received, read it (receiveDatagram()) and then cancel existing 5 second timer and call function to restart a new one.

    ?

    Alternatively, if http://doc.qt.io/qt-5/qabstractsocket.html#waitForReadyRead works for your UDP (and note it's not reliable if you are Windows anyway), you might architect using http://doc.qt.io/qt-5/qabstractsocket.html#waitForReadyRead specifying your 5,000ms, but you'll probably end up with using earlier methof.



  • @samy03 said in QUdpSocket multicast receiver timeout detection?:

    @JonB I tried both methods but none of them are working.
    With the first method, as soon as I start receiving multicast message, my program shutdown.

    With waitForReadyRead, nothing was happening, even though its on Linux.



  • @samy03
    Since the docs state that waitForReadyRead() may be flaky (although it says only under Windows), let's not use that. In any case it doesn't do anything we cannot do ourselves.

    As for:

    With the first method, as soon as I start receiving multicast message, my program shutdown.

    Well, you know your program should not "shutdown" in such a situation! So either examine your own code, or show us a minimal example of what does not work for you?



  • @JonB
    Here is my code:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QtWidgets>
    #include <QtNetwork>
    #include <QXmlStreamReader>
    #include "SimpleGPIO.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
        setWindowState(Qt::WindowFullScreen);
    
        gpio_omap_mux_setup("eCAP0_in_PWM0", "128"); 	//gpio1_28 P9 header pin# 12
     this->GREEN_LED_PIN = 60;  
            gpio_export(this->GREEN_LED_PIN);
            gpio_set_dir(this->GREEN_LED_PIN, OUTPUT_PIN);
            ::gpio_set_value(this->GREEN_LED_PIN, HIGH);
    
    	xmltimer(); 	//starting timer
    
            groupAddress = QHostAddress("224.224.24.23");
    
            udpSocket = new QUdpSocket(this); udpSocket->bind(QHostAddress::AnyIPv4, 11007, QUdpSocket::ShareAddress);
            udpSocket->joinMulticastGroup(groupAddress);
    
            connect(udpSocket, SIGNAL(readyRead()),
                    this, SLOT(processPendingDatagrams()));
                
    }
    
     void MainWindow::processPendingDatagrams()
        {
            while (udpSocket->hasPendingDatagrams())
            {
                QByteArray datagram;
                datagram.resize(udpSocket->pendingDatagramSize());
                udpSocket->readDatagram(datagram.data(), datagram.size());
                str=datagram;
    
                QXmlStreamReader xml(str);
    
                timer->stop(); //stopping the timer
                xmltimer(); //calling the timer again
    
                //Parse the XML until we reach end of it
                while(!xml.atEnd() && !xml.hasError()) {
                        // Read next element
                QXmlStreamReader::TokenType token = xml.readNext();
                        //If token is just StartDocument - go to next
                        if(token == QXmlStreamReader::StartDocument) {
                                continue;
                        }
    		}
    	}
        }
    
      void MainWindow::nomsg()
         {
    
             ::gpio_set_value(this->GREEN_LED_PIN, HIGH);
    
         }
    
      void MainWindow::xmltimer()
         {
    
                QTimer::singleShot(5000, this, SLOT(nomsg()));
    
         }
    

    This is just a minimal example of what I am trying to achieve here.



  • @samy03
    And? I don't know how it performs. You can put some qDebug()s in, or use the debugger, to see what is actually doing, surely?

    After your code has exited MainWindow::MainWindow(), I assume your caller does go into the normal Qt event loop, it doesn't just exit?



  • @samy03 said in QUdpSocket multicast receiver timeout detection?:

    I am using multicast receiver example

    I'd just modify the existing processPendingDatagrams() method (receiver.cpp) to handle the timer start/stop actions... pseudo-code (not tested):

    ...
    QTimer timerLostSignal = QTimer(5000);
    QObject::connect(timerLostSignal, &QTimer::timeout, this, &MainWindow::noMsg);
    // start checking if no datagrams are received
    timerLostSignal.start();
    ...
    ...
    void Receiver::processPendingDatagrams()
    {
        // since we're going to read datagrams
        // stop timer (signal is not lost yet...)
        timerLostSignal.stop();
    
        QByteArray datagram;
        while (udpSocket->hasPendingDatagrams()) {
            datagram.resize(int(udpSocket->pendingDatagramSize()));
            udpSocket->readDatagram(datagram.data(), datagram.size());
            statusLabel->setText(tr("Received datagram: \"%1\"")
                                 .arg(datagram.constData()));
        }
        // loop finished, no more datagrams to read so far
        // start timer just in case no other datagram arrives ever
        timerLostSignal.start();
    }
    ...
    ...
    void MainWindow::noMsg()
    {
    ::gpio_set_value(this->GREEN_LED_PIN, HIGH);
    }
    
    


  • I got it working just by changing the format of my timer like this:

    newtimer = new QTimer(this);
    newtimer->setInterval(3000);
    newtimer->setSingleShot(true);
    connect(newtimer, SIGNAL(timeout()), SLOT(nomsg()));
    newtimer->start();
    

    and then calling newtimer to start or stop.

    I had to do this since you cannot start or stop SingleShot timer in this "QTimer::singleShot(200, this, SLOT(updateCaption()));" format.


Log in to reply