Как сделать «переключение мертвецов» в Qt? - PullRequest
0 голосов
/ 24 января 2019

Я хочу контролировать периодическое действие, чтобы я мог что-то сделать, когда оно остановится.Например, переключитесь на локальный таймер, чтобы сохранить это действие, и переключитесь обратно на первичный источник, когда он снова запустится.

Лучший теоретический пример, который я могу придумать, это:

#define FRAME_INTERVAL_MSEC     33  // ~30Hz
bool periodFromUSB;
QTimer* myTimer;

void Processing::localTimeout()
{
    //connected to myTimer->timeout();
    if (periodFromUSB)
    {
        periodFromUSB = false;
        myTimer->stop();
        myTimer->setSingleShot(false);
        myTimer->setInterval(FRAME_INTERVAL_MSEC);
        myTimer->start();
    }

    processDMX();
}

void Processing::newFrame()
{
    //called periodically from my USB driver
    myTimer->stop();
    if(!periodFromUSB)
    {
        periodFromUSB = true;
        myTimer->setSingleShot(true);
        myTimer->setInterval(FRAME_INTERVAL_MSEC * 2);
    }
    myTimer->start();

    processDMX();
}

Но как бы я ни организовал это, я продолжаю вызывать обе функции, когда мой USB-драйвер работает.(точка останова в любом месте приведенного выше кода сразу попадает)

Есть ли лучший способ сделать мертвец?

1 Ответ

0 голосов
/ 24 января 2019

Если вы вызываете start (), таймер будет сброшен на 0 и перезапустит текущий интервал. То есть до тех пор, пока ваш слот newFrame () будет вызван до истечения времени ожидания, localTimeout () никогда не будет вызываться.

Ваш код будет выглядеть так:

#define FRAME_INTERVAL_MSEC     33  // ~30Hz
bool periodFromUSB;
QTimer* myTimer;

void Processing::localTimeout()
{
    //connected to myTimer->timeout();
    if (periodFromUSB)
    {
        periodFromUSB = false;
    }

    processDMX();
}

void Processing::newFrame()
{
    //called periodically from my USB driver
    if(!periodFromUSB)
    {
        periodFromUSB = true;
    }
    myTimer->start(); // restarts current timer interval

    processDMX();

    // for debugging: display actual interval length in milliseconds:
    static qint64 start = QDateTime::currentMSecsSinceEpoch();
    static qint64 count = 0;
    ++count;
    qint64 curr = QDateTime::currentMSecsSinceEpoch();
    float msecsPerInterval = float(curr - start) / float(count);
    qDebug() << "msecs per interval: " << msecsPerInterval;
}

void Processing::init()
{
    myTimer = new QTimer();
    connect(myTimer, &QTimer::timeout, this, &Processing::newFrame);
    myTimer->setInterval(FRAME_INTERVAL_MSEC);
    myTimer->start();
}

Если ваш слот localTimeout () по-прежнему вызывается, ваш FRAME_INTERVAL_MSEC слишком мал.

Вы можете проверить это, используя код отладки, который я добавил к newFrame().

Это может быть потому, что:

  • ваш USB-драйвер получает данные слишком редко или
  • обработка в processDMX() занимает слишком много времени (если длительность processDMX() больше, чем FRAME_INTERVAL_MSEC, следующий слот не будет вызван вовремя)
...