Files
giesCANne/frameplaybackobject.cpp
T

457 lines
13 KiB
C++

#include "frameplaybackobject.h"
#include <algorithm>
FramePlaybackObject::FramePlaybackObject()
{
mThread_p = new QThread();
currentPosition = 0;
playbackInterval = 1;
playbackBurst = 1;
statusCounter = 0;
numBuses = 0;
playbackActive = false;
playbackForward = true;
useOrigTiming = true;
whichBusSend = 0;
currentSeqItem = nullptr;
}
FramePlaybackObject::~FramePlaybackObject()
{
mThread_p->quit();
mThread_p->wait();
delete mThread_p;
}
quint64 FramePlaybackObject::updatePosition(bool forward)
{
//qDebug() << "updatePosition";
if (!currentSeqItem) {
playbackTimer->stop(); //pushing this button halts automatic playback
playbackActive = false;
currentPosition = 0;
return 0;
}
//only send frame out if its ID is checked in the list. Otherwise discard it.
CANFrame *thisFrame = &currentSeqItem->data[currentPosition];
uint32_t originalBus = thisFrame->bus;
if (currentSeqItem->idFilters.find(thisFrame->frameId()).value())
{
if (whichBusSend > -1)
{
thisFrame->bus = whichBusSend;
sendingBuffer.append(*thisFrame);
}
else if (whichBusSend == -1)
{
for (int c = 0; c < numBuses; c++)
{
thisFrame->bus = c;
sendingBuffer.append(*thisFrame);
}
}
else //from file so retain original bus and send as-is
{
sendingBuffer.append(*thisFrame);
}
thisFrame->bus = originalBus;
}
if (forward)
{
if (currentPosition < (currentSeqItem->data.count() - 1)) currentPosition++; //still in same file so keep going
else //hit the end of the current file
{
qDebug() << "hit end of current sequence";
currentSeqItem->currentLoopCount++;
currentPosition = 0;
if (currentSeqItem->currentLoopCount == currentSeqItem->maxLoops) //have we looped enough times?
{
playbackActive = false;
playbackTimer->stop();
emit EndOfFrameCache();
}
}
}
else
{
if (currentPosition > 0) currentPosition--;
else //hit the beginning of the current sequence
{
qDebug() << "hit start of current sequence";
currentSeqItem->currentLoopCount++;
currentPosition = currentSeqItem->data.count() - 1;
if (currentSeqItem->currentLoopCount == currentSeqItem->maxLoops) //have we looped enough times?
{
playbackActive = false;
playbackTimer->stop();
emit EndOfFrameCache();
}
}
}
return thisFrame->timeStamp().microSeconds();
}
quint64 FramePlaybackObject::peekPosition(bool forward)
{
int peekCurrentPosition = currentPosition;
if (forward)
{
if (peekCurrentPosition < (currentSeqItem->data.count() - 1)) peekCurrentPosition++; //still in same file so keep going
else //hit the end of the current file
{
return 0xFFFFFFFFFFFFFFFFull;
}
}
else
{
if (peekCurrentPosition > 0) peekCurrentPosition--;
else //hit the beginning of the current sequence
{
return 0xFFFFFFFFFFFFFFFFull;
}
}
CANFrame *thisFrame = &currentSeqItem->data[peekCurrentPosition];
return thisFrame->timeStamp().microSeconds();
}
void FramePlaybackObject::piStart()
{
playbackTimer = new QTimer();
playbackTimer->setTimerType(Qt::PreciseTimer);
playbackTimer->setInterval(1);
currentPosition = 0;
playbackActive = false;
playbackForward = true;
whichBusSend = 0;
connect(playbackTimer, &QTimer::timeout, this, &FramePlaybackObject::timerTriggered);
}
void FramePlaybackObject::piStop()
{
playbackTimer->stop();
delete playbackTimer;
}
void FramePlaybackObject::initialize()
{
if( mThread_p && (mThread_p != QThread::currentThread()) )
{
/* move ourself to the thread */
moveToThread(mThread_p); /*TODO handle errors */
/* connect started() */
connect(mThread_p, SIGNAL(started()), this, SLOT(initialize()));
/* start the thread */
mThread_p->start(QThread::HighPriority);
return;
}
/* set started flag */
//mStarted = true;
/* in multithread case, this will be called before entering thread event loop */
return piStart();
}
void FramePlaybackObject::finalize()
{
/* 1) execute in mThread_p context */
if( mThread_p && (mThread_p != QThread::currentThread()) )
{
/* if thread is finished, it means we call this function for the second time so we can leave */
if( !mThread_p->isFinished() )
{
/* we need to call piStop() */
QMetaObject::invokeMethod(this, "finalize",
Qt::BlockingQueuedConnection);
/* 3) stop thread */
mThread_p->quit();
if(!mThread_p->wait()) {
qDebug() << "can't stop thread";
}
}
return;
}
/* 2) call piStop in mThread context */
return piStop();
}
void FramePlaybackObject::startPlaybackForward()
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "startPlaybackForward",
Qt::BlockingQueuedConnection);
return;
}
playbackActive = true;
playbackForward = true;
if (useOrigTiming)
{
playbackTimer->setInterval(1);
playbackElapsed.start();
if (currentSeqItem->data[currentPosition].timeStamp().microSeconds() > 2000)
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timeStamp().microSeconds() - 2000;
else playbackLastTimeStamp = 0;
}
playbackTimer->start();
}
void FramePlaybackObject::startPlaybackBackward()
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "startPlaybackBackward",
Qt::BlockingQueuedConnection);
return;
}
playbackActive = true;
playbackForward = false;
if (useOrigTiming)
{
playbackElapsed.start();
playbackTimer->setInterval(1);
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timeStamp().microSeconds() + 2000;
}
playbackTimer->start();
}
void FramePlaybackObject::stepPlaybackForward()
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "stepPlaybackForward",
Qt::BlockingQueuedConnection);
return;
}
sendingBuffer.clear();
playbackTimer->stop();
playbackActive = false;
updatePosition(true);
CANConManager::getInstance()->sendFrames(sendingBuffer);
emit statusUpdate(currentPosition);
}
void FramePlaybackObject::stepPlaybackBackward()
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "stepPlaybackBackward",
Qt::BlockingQueuedConnection);
return;
}
sendingBuffer.clear();
playbackTimer->stop(); //pushing this button halts automatic playback
playbackActive = false;
updatePosition(false);
CANConManager::getInstance()->sendFrames(sendingBuffer);
emit statusUpdate(currentPosition);
}
void FramePlaybackObject::stopPlayback()
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "stopPlayback",
Qt::BlockingQueuedConnection);
return;
}
playbackTimer->stop(); //pushing this button halts automatic playback
playbackActive = false;
currentPosition = 0;
emit statusUpdate(currentPosition);
}
void FramePlaybackObject::pausePlayback()
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "pausePlayback",
Qt::BlockingQueuedConnection);
return;
}
playbackActive = false;
playbackTimer->stop();
emit statusUpdate(currentPosition);
}
void FramePlaybackObject::seekPlayback(double timestamp)
{
if (currentSeqItem == NULL)
return;
/* make sure we execute in mThread context */
if (mThread_p && (mThread_p != QThread::currentThread()))
{
// TODO fix for QT5 from customizing branch
// QMetaObject::invokeMethod(this, "seekPlayback", Qt::BlockingQueuedConnection, timestamp);
return;
}
// playbackTimer->stop();
// playbackActive = false;
timestamp *= 1000000; // convert to us
size_t lowIdx = 0;
size_t highIdx = currentSeqItem->data.count() - 1;
while (lowIdx < highIdx)
{
int midIdx = lowIdx + (highIdx - lowIdx) / 2;
CANFrame midFrame = currentSeqItem->data[midIdx];
if (midFrame.timeStamp().seconds() * 1000000 + midFrame.timeStamp().microSeconds() < timestamp)
{
lowIdx = midIdx + 1;
}
else
{
highIdx = midIdx - 1;
}
}
currentPosition = lowIdx;
emit statusUpdate(currentPosition);
startPlaybackForward();
}
void FramePlaybackObject::setSequenceObject(SequenceItem *item)
{
currentSeqItem = item;
}
void FramePlaybackObject::setUseOriginalTiming(bool state)
{
useOrigTiming = state;
}
void FramePlaybackObject::setSendingBus(int bus)
{
qDebug() << "Setting sending bus to " << bus;
whichBusSend = bus;
}
void FramePlaybackObject::setPlaybackBurst(int burst)
{
playbackBurst = burst;
}
void FramePlaybackObject::setNumBuses(int buses)
{
numBuses = buses;
}
//any time you touch objects that live in a potentially different thread you must switch into that thread.
//So this function is a bit different than the rest of the simple setters for that reason.
void FramePlaybackObject::setPlaybackInterval(int interval)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "setPlaybackInterval",
Qt::BlockingQueuedConnection,
Q_ARG(int , interval) );
return;
}
playbackInterval = interval;
playbackTimer->setInterval(interval);
}
void FramePlaybackObject::timerTriggered()
{
sendingBuffer.clear();
if (useOrigTiming)
{
//get elapsed microseconds since last tick (in case timer skips or is otherwise inaccurate, though there are no guarantees about elapsed timer either)
quint64 elapsed = playbackElapsed.nsecsElapsed() / 1000;
playbackElapsed.start();
if (playbackForward)
{
playbackLastTimeStamp += elapsed;
//qDebug() << playbackLastTimeStamp;
//qDebug() << "El: " << elapsed;
while (peekPosition(true) <= playbackLastTimeStamp)
{
updatePosition(true);
}
if (peekPosition(true) == 0xFFFFFFFFFFFFFFFFull)
{
updatePosition(true); //this'll go to the next log (if there is one)
if (currentSeqItem->data[currentPosition].timeStamp().microSeconds() > 1000)
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timeStamp().microSeconds() - 1000;
else playbackLastTimeStamp = 0;
}
}
else
{
if (playbackLastTimeStamp > elapsed)
playbackLastTimeStamp -= elapsed;
else playbackLastTimeStamp = 0;
while (peekPosition(false) >= playbackLastTimeStamp && peekPosition(false) != 0xFFFFFFFFFFFFFFFFull)
{
updatePosition(false);
}
if (peekPosition(false) == 0xFFFFFFFFFFFFFFFFull)
{
updatePosition(false); //this'll go to the next log (if there is one)
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timeStamp().microSeconds() + 1000;
}
}
statusCounter++;
}
else
{
for (int count = 0; count < playbackBurst; count++)
{
if (!playbackActive)
{
playbackTimer->stop();
return;
}
if (playbackForward)
{
updatePosition(true);
}
else
{
updatePosition(false);
}
}
statusCounter += playbackInterval;
}
if (statusCounter > 100)
{
statusCounter = 0;
emit statusUpdate(currentPosition);
}
//qDebug() << "sb: " << sendingBuffer.count();
if (sendingBuffer.count() > 0) CANConManager::getInstance()->sendFrames(sendingBuffer);
}