I want to monitor a periodic action so that I can do something when it stops. For example, switch to a local timer to keep that action going, and switch back to the primary source when it starts back up again.
The best theoretical example that I can come up with is this:
#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();
}
But no matter how I arrange it, I keep getting both functions called when my USB driver is running. (a breakpoint anywhere in the code above is hit immediately)
Is there a better way to do a deadman?
If you call start(), the timer will be reset to 0 and restart the current interval. That is, as long as your newFrame() slot gets called before the timeout is reached, localTimeout() will never be called.
Your code would then look like this:
#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();
}
If your localTimeout() slot still gets called, your FRAME_INTERVAL_MSEC is too low.
You can check this by using the debugging code I added to newFrame()
.
This can be because:
processDMX()
takes too long (if the duration of processDMX()
is longer than FRAME_INTERVAL_MSEC, the next slot doesn't get called in time)