414 lines
12 KiB
C++
414 lines
12 KiB
C++
#include "frameplaybackobject.h"
|
|
|
|
FramePlaybackObject::FramePlaybackObject()
|
|
{
|
|
mThread_p = new QThread();
|
|
|
|
currentPosition = 0;
|
|
playbackInterval = 1;
|
|
playbackBurst = 1;
|
|
statusCounter = 0;
|
|
numBuses = 0;
|
|
playbackActive = false;
|
|
playbackForward = true;
|
|
useOrigTiming = false;
|
|
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 = ¤tSeqItem->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 = ¤tSeqItem->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::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 > 249)
|
|
{
|
|
statusCounter = 0;
|
|
emit statusUpdate(currentPosition);
|
|
}
|
|
|
|
//qDebug() << "sb: " << sendingBuffer.count();
|
|
if (sendingBuffer.count() > 0) CANConManager::getInstance()->sendFrames(sendingBuffer);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|