Moved a lot of the frame playback window functionality to a new class. This allows the functionality to be run
on a separate thread. The performance is a lot better and "use original timing" is now reasonably accurate.
This commit is contained in:
+4
-2
@@ -64,7 +64,8 @@ SOURCES += main.cpp\
|
|||||||
bus_protocols/isotp_handler.cpp \
|
bus_protocols/isotp_handler.cpp \
|
||||||
bus_protocols/j1939_handler.cpp \
|
bus_protocols/j1939_handler.cpp \
|
||||||
bus_protocols/uds_handler.cpp \
|
bus_protocols/uds_handler.cpp \
|
||||||
jsedit.cpp
|
jsedit.cpp \
|
||||||
|
frameplaybackobject.cpp
|
||||||
|
|
||||||
HEADERS += mainwindow.h \
|
HEADERS += mainwindow.h \
|
||||||
can_structs.h \
|
can_structs.h \
|
||||||
@@ -117,7 +118,8 @@ HEADERS += mainwindow.h \
|
|||||||
bus_protocols/j1939_handler.h \
|
bus_protocols/j1939_handler.h \
|
||||||
bus_protocols/uds_handler.h \
|
bus_protocols/uds_handler.h \
|
||||||
bus_protocols/isotp_message.h \
|
bus_protocols/isotp_message.h \
|
||||||
jsedit.h
|
jsedit.h \
|
||||||
|
frameplaybackobject.h
|
||||||
|
|
||||||
FORMS += ui/candatagrid.ui \
|
FORMS += ui/candatagrid.ui \
|
||||||
ui/connectionwindow.ui \
|
ui/connectionwindow.ui \
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ void ConnectionWindow::showEvent(QShowEvent* event)
|
|||||||
readSettings();
|
readSettings();
|
||||||
ui->tableConnections->selectRow(0);
|
ui->tableConnections->selectRow(0);
|
||||||
currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex());
|
currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex());
|
||||||
|
handleConnTypeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionWindow::closeEvent(QCloseEvent *event)
|
void ConnectionWindow::closeEvent(QCloseEvent *event)
|
||||||
|
|||||||
@@ -0,0 +1,456 @@
|
|||||||
|
#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 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FramePlaybackObject::~FramePlaybackObject()
|
||||||
|
{
|
||||||
|
mThread_p->quit();
|
||||||
|
mThread_p->wait();
|
||||||
|
delete mThread_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 FramePlaybackObject::updatePosition(bool forward)
|
||||||
|
{
|
||||||
|
//qDebug() << "updatePosition";
|
||||||
|
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();
|
||||||
|
/*
|
||||||
|
currentSeqNum++; //go forward in the sequence
|
||||||
|
if (currentSeqNum == seqItems.count()) //are we at the end of the sequence?
|
||||||
|
{
|
||||||
|
//reset the loop figures for each sequence entry
|
||||||
|
for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0;
|
||||||
|
currentSeqNum = 0;
|
||||||
|
if (ui->cbLoop->isChecked()) //go back to beginning if we're looping the sequence
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else //not looping so stop playback entirely
|
||||||
|
{
|
||||||
|
playbackActive = false;
|
||||||
|
playbackTimer->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentSeqItem = &seqItems[currentSeqNum];
|
||||||
|
ui->tblSequence->setCurrentCell(currentSeqNum, 0);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
|
||||||
|
/*
|
||||||
|
currentSeqNum--; //go backward in the sequence
|
||||||
|
if (currentSeqNum == -1) //are we trying to go past the beginning?
|
||||||
|
{
|
||||||
|
//reset the loop figures for each sequence entry
|
||||||
|
for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0;
|
||||||
|
currentSeqNum = seqItems.count() - 1;
|
||||||
|
if (ui->cbLoop->isChecked()) //go back to the last sequence entry if we're looping
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else //not looping so stop playback entirely
|
||||||
|
{
|
||||||
|
playbackActive = false;
|
||||||
|
playbackTimer->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentSeqItem = &seqItems[currentSeqNum];
|
||||||
|
ui->tblSequence->setCurrentCell(currentSeqNum, 0);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//updateFrameLabel();
|
||||||
|
//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->ID).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;
|
||||||
|
}
|
||||||
|
return thisFrame->timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 > 2000)
|
||||||
|
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 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 + 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
/*
|
||||||
|
if (seqItems.count() > 0)
|
||||||
|
{
|
||||||
|
currentSeqNum = 0;
|
||||||
|
currentSeqItem = &seqItems[currentSeqNum];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentSeqNum = -1;
|
||||||
|
currentSeqItem = NULL;
|
||||||
|
}
|
||||||
|
if (ui->tblSequence->rowCount() > 0)
|
||||||
|
{
|
||||||
|
ui->tblSequence->setCurrentCell(0, 0);
|
||||||
|
refreshIDList();
|
||||||
|
}
|
||||||
|
updateFrameLabel(); */
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramePlaybackObject::setSequenceObject(SequenceItem *item)
|
||||||
|
{
|
||||||
|
currentSeqItem = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramePlaybackObject::setUseOriginalTiming(bool state)
|
||||||
|
{
|
||||||
|
useOrigTiming = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramePlaybackObject::setSendingBus(int 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 > 1000)
|
||||||
|
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 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 + 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
#ifndef FRAMEPLAYBACKOBJECT_H
|
||||||
|
#define FRAMEPLAYBACKOBJECT_H
|
||||||
|
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "can_structs.h"
|
||||||
|
#include "connections/canconmanager.h"
|
||||||
|
|
||||||
|
//one entry in the sequence of data to use
|
||||||
|
struct SequenceItem
|
||||||
|
{
|
||||||
|
QString filename;
|
||||||
|
QVector<CANFrame> data;
|
||||||
|
QHash<int, bool> idFilters;
|
||||||
|
int maxLoops;
|
||||||
|
int currentLoopCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
broken out functionality that used to be in frameplaybackwindow. That mixed code for Model/View/Controller into one giant
|
||||||
|
class. I wasn't too concerned about that but the problem is that all code within a GUI object runs in GUI context and that
|
||||||
|
is most certainly not a feature, especially if you have a multi-core CPU. This object lives in a separate thread from the GUI
|
||||||
|
and thus is better scheduled and doesn't block the GUI thread. Really all functionality in this program should be broken into
|
||||||
|
a separate thread from GUI if it is prone to running a long time and/or taking up a lot of CPU time (unless it really does
|
||||||
|
have to interface with the GUI in some way. All gui touching code must run on its thread).
|
||||||
|
*/
|
||||||
|
class FramePlaybackObject : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FramePlaybackObject();
|
||||||
|
~FramePlaybackObject();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* @brief start the device. This calls piStarted
|
||||||
|
* @note starts the working thread if required (piStart is called in the working thread context)
|
||||||
|
*/
|
||||||
|
void initialize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief stop the device. This calls piStop
|
||||||
|
* @note if a working thread is used, piStop is called before exiting the working thread
|
||||||
|
*/
|
||||||
|
void finalize();
|
||||||
|
|
||||||
|
void startPlaybackForward();
|
||||||
|
void startPlaybackBackward();
|
||||||
|
void stepPlaybackForward();
|
||||||
|
void stepPlaybackBackward();
|
||||||
|
void stopPlayback();
|
||||||
|
void pausePlayback();
|
||||||
|
|
||||||
|
void setSequenceObject(SequenceItem *item);
|
||||||
|
void setUseOriginalTiming(bool state);
|
||||||
|
void setSendingBus(int bus);
|
||||||
|
void setPlaybackInterval(int interval);
|
||||||
|
void setPlaybackBurst(int burst);
|
||||||
|
void setNumBuses(int buses);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void EndOfFrameCache(); //we hit the end/beginning of the frame cache (depending on direction of playback)
|
||||||
|
void statusUpdate(int frameNum);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void timerTriggered();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<CANFrame> sendingBuffer;
|
||||||
|
SequenceItem *currentSeqItem;
|
||||||
|
int currentPosition;
|
||||||
|
QTimer *playbackTimer;
|
||||||
|
QElapsedTimer playbackElapsed;
|
||||||
|
quint64 playbackLastTimeStamp;
|
||||||
|
int playbackInterval;
|
||||||
|
int playbackBurst;
|
||||||
|
int numBuses;
|
||||||
|
int statusCounter;
|
||||||
|
bool playbackActive;
|
||||||
|
bool playbackForward;
|
||||||
|
bool useOrigTiming;
|
||||||
|
int whichBusSend;
|
||||||
|
QThread* mThread_p;
|
||||||
|
|
||||||
|
quint64 updatePosition(bool forward);
|
||||||
|
quint64 peekPosition(bool forward);
|
||||||
|
/**
|
||||||
|
* @brief starts the device
|
||||||
|
*/
|
||||||
|
void piStart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief stops the device
|
||||||
|
*/
|
||||||
|
void piStop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FRAMEPLAYBACKOBJECT_H
|
||||||
+64
-239
@@ -32,19 +32,17 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, QWidge
|
|||||||
ui->comboCANBus->addItem(tr("From File"));
|
ui->comboCANBus->addItem(tr("From File"));
|
||||||
ui->comboCANBus->setCurrentIndex(0);
|
ui->comboCANBus->setCurrentIndex(0);
|
||||||
|
|
||||||
|
playbackObject.initialize();
|
||||||
|
playbackObject.setNumBuses(numBuses);
|
||||||
|
|
||||||
readSettings();
|
readSettings();
|
||||||
|
|
||||||
modelFrames = frames;
|
modelFrames = frames;
|
||||||
|
|
||||||
playbackTimer = new QTimer();
|
|
||||||
playbackTimer->setTimerType(Qt::PreciseTimer);
|
|
||||||
|
|
||||||
currentPosition = 0;
|
|
||||||
playbackActive = false;
|
|
||||||
playbackForward = true;
|
|
||||||
whichBusSend = 0; //0 = no bus, 1 = bus 0, 2 = bus 1, 4 = from file - Bitfield so you can 'or' them.
|
|
||||||
currentSeqItem = NULL;
|
currentSeqItem = NULL;
|
||||||
currentSeqNum = -1;
|
currentSeqNum = -1;
|
||||||
|
currentPosition = 0;
|
||||||
|
forward = true;
|
||||||
|
|
||||||
updateFrameLabel();
|
updateFrameLabel();
|
||||||
|
|
||||||
@@ -58,10 +56,10 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, QWidge
|
|||||||
connect(ui->btnSelectNone, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectNoneClick);
|
connect(ui->btnSelectNone, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectNoneClick);
|
||||||
connect(ui->btnDelete, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnDeleteCurrSeq);
|
connect(ui->btnDelete, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnDeleteCurrSeq);
|
||||||
connect(ui->spinPlaySpeed, SIGNAL(valueChanged(int)), this, SLOT(changePlaybackSpeed(int)));
|
connect(ui->spinPlaySpeed, SIGNAL(valueChanged(int)), this, SLOT(changePlaybackSpeed(int)));
|
||||||
|
connect(ui->spinBurstSpeed, SIGNAL(valueChanged(int)), this, SLOT(changeBurstRate(int)));
|
||||||
//connect(ui->cbLoop, SIGNAL(clicked(bool)), this, SLOT(changeLooping(bool)));
|
//connect(ui->cbLoop, SIGNAL(clicked(bool)), this, SLOT(changeLooping(bool)));
|
||||||
connect(ui->comboCANBus, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSendingBus(int)));
|
connect(ui->comboCANBus, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSendingBus(int)));
|
||||||
connect(ui->listID, &QListWidget::itemClicked, this, &FramePlaybackWindow::changeIDFiltering);
|
connect(ui->listID, &QListWidget::itemClicked, this, &FramePlaybackWindow::changeIDFiltering);
|
||||||
connect(playbackTimer, &QTimer::timeout, this, &FramePlaybackWindow::timerTriggered);
|
|
||||||
connect(ui->btnLoadFile, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadFile);
|
connect(ui->btnLoadFile, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadFile);
|
||||||
connect(ui->btnLoadLive, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadLive);
|
connect(ui->btnLoadLive, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadLive);
|
||||||
connect(ui->tblSequence, &QTableWidget::cellPressed, this, &FramePlaybackWindow::seqTableCellClicked);
|
connect(ui->tblSequence, &QTableWidget::cellPressed, this, &FramePlaybackWindow::seqTableCellClicked);
|
||||||
@@ -70,10 +68,13 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, QWidge
|
|||||||
connect(ui->btnSaveFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::saveFilters);
|
connect(ui->btnSaveFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::saveFilters);
|
||||||
connect(ui->cbOriginalTiming, &QCheckBox::toggled, this, &FramePlaybackWindow::useOrigTimingClicked);
|
connect(ui->cbOriginalTiming, &QCheckBox::toggled, this, &FramePlaybackWindow::useOrigTimingClicked);
|
||||||
|
|
||||||
|
connect(&playbackObject, &FramePlaybackObject::EndOfFrameCache, this, &FramePlaybackWindow::EndOfFrameCache);
|
||||||
|
connect(&playbackObject, &FramePlaybackObject::statusUpdate, this, &FramePlaybackWindow::getStatusUpdate);
|
||||||
|
|
||||||
ui->listID->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->listID->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(ui->listID, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuFilters(QPoint)));
|
connect(ui->listID, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuFilters(QPoint)));
|
||||||
|
|
||||||
playbackTimer->setInterval(ui->spinPlaySpeed->value()); //set the timer to the default value of the control
|
playbackObject.setPlaybackInterval(ui->spinPlaySpeed->value());
|
||||||
|
|
||||||
QStringList headers;
|
QStringList headers;
|
||||||
headers << "Source" << "Loops";
|
headers << "Source" << "Loops";
|
||||||
@@ -86,9 +87,6 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, QWidge
|
|||||||
FramePlaybackWindow::~FramePlaybackWindow()
|
FramePlaybackWindow::~FramePlaybackWindow()
|
||||||
{
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
|
|
||||||
playbackTimer->stop();
|
|
||||||
delete playbackTimer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::showEvent(QShowEvent *)
|
void FramePlaybackWindow::showEvent(QShowEvent *)
|
||||||
@@ -116,7 +114,8 @@ void FramePlaybackWindow::readSettings()
|
|||||||
}
|
}
|
||||||
ui->spinPlaySpeed->setValue(settings.value("Playback/DefSpeed", 5).toInt());
|
ui->spinPlaySpeed->setValue(settings.value("Playback/DefSpeed", 5).toInt());
|
||||||
ui->comboCANBus->setCurrentIndex(settings.value("Playback/SendingBus", 0).toInt());
|
ui->comboCANBus->setCurrentIndex(settings.value("Playback/SendingBus", 0).toInt());
|
||||||
whichBusSend = ui->comboCANBus->currentIndex();
|
|
||||||
|
calculateWhichBus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::writeSettings()
|
void FramePlaybackWindow::writeSettings()
|
||||||
@@ -257,6 +256,35 @@ void FramePlaybackWindow::refreshIDList()
|
|||||||
ui->listID->sortItems();
|
ui->listID->sortItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FramePlaybackWindow::calculateWhichBus()
|
||||||
|
{
|
||||||
|
int idx = ui->comboCANBus->currentIndex();
|
||||||
|
int maxIdx = ui->comboCANBus->count() - 1;
|
||||||
|
int out = idx;
|
||||||
|
if (idx == (maxIdx - 1) ) out = -1;
|
||||||
|
if (idx == maxIdx) out = -2;
|
||||||
|
|
||||||
|
playbackObject.setSendingBus(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramePlaybackWindow::EndOfFrameCache()
|
||||||
|
{
|
||||||
|
if (forward)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramePlaybackWindow::getStatusUpdate(int frameNum)
|
||||||
|
{
|
||||||
|
currentPosition = frameNum;
|
||||||
|
updateFrameLabel();
|
||||||
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::updateFrameLabel()
|
void FramePlaybackWindow::updateFrameLabel()
|
||||||
{
|
{
|
||||||
int row = currentSeqNum;
|
int row = currentSeqNum;
|
||||||
@@ -320,11 +348,13 @@ void FramePlaybackWindow::useOrigTimingClicked()
|
|||||||
{
|
{
|
||||||
ui->spinBurstSpeed->setEnabled(false);
|
ui->spinBurstSpeed->setEnabled(false);
|
||||||
ui->spinPlaySpeed->setEnabled(false);
|
ui->spinPlaySpeed->setEnabled(false);
|
||||||
|
playbackObject.setUseOriginalTiming(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ui->spinBurstSpeed->setEnabled(true);
|
ui->spinBurstSpeed->setEnabled(true);
|
||||||
ui->spinPlaySpeed->setEnabled(true);
|
ui->spinPlaySpeed->setEnabled(true);
|
||||||
|
playbackObject.setUseOriginalTiming(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,11 +362,7 @@ void FramePlaybackWindow::btnDeleteCurrSeq()
|
|||||||
{
|
{
|
||||||
if (currentSeqNum == -1) return;
|
if (currentSeqNum == -1) return;
|
||||||
|
|
||||||
if (playbackActive)
|
playbackObject.stopPlayback();
|
||||||
{
|
|
||||||
playbackActive = false;
|
|
||||||
playbackTimer->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
seqItems.removeAt(currentSeqNum);
|
seqItems.removeAt(currentSeqNum);
|
||||||
ui->tblSequence->removeRow(currentSeqNum);
|
ui->tblSequence->removeRow(currentSeqNum);
|
||||||
@@ -380,6 +406,7 @@ void FramePlaybackWindow::btnLoadFile()
|
|||||||
{
|
{
|
||||||
currentSeqNum = 0;
|
currentSeqNum = 0;
|
||||||
currentSeqItem = &seqItems[0];
|
currentSeqItem = &seqItems[0];
|
||||||
|
playbackObject.setSequenceObject(currentSeqItem);
|
||||||
}
|
}
|
||||||
refreshIDList();
|
refreshIDList();
|
||||||
updateFrameLabel();
|
updateFrameLabel();
|
||||||
@@ -408,6 +435,7 @@ void FramePlaybackWindow::btnLoadLive()
|
|||||||
{
|
{
|
||||||
currentSeqNum = 0;
|
currentSeqNum = 0;
|
||||||
currentSeqItem = &seqItems[0];
|
currentSeqItem = &seqItems[0];
|
||||||
|
playbackObject.setSequenceObject(currentSeqItem);
|
||||||
}
|
}
|
||||||
refreshIDList();
|
refreshIDList();
|
||||||
updateFrameLabel();
|
updateFrameLabel();
|
||||||
@@ -416,38 +444,24 @@ void FramePlaybackWindow::btnLoadLive()
|
|||||||
|
|
||||||
void FramePlaybackWindow::btnBackOneClick()
|
void FramePlaybackWindow::btnBackOneClick()
|
||||||
{
|
{
|
||||||
sendingBuffer.clear();
|
forward = false;
|
||||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
playbackObject.stepPlaybackBackward();
|
||||||
playbackActive = false;
|
|
||||||
|
|
||||||
updatePosition(false);
|
|
||||||
CANConManager::getInstance()->sendFrames(sendingBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::btnPauseClick()
|
void FramePlaybackWindow::btnPauseClick()
|
||||||
{
|
{
|
||||||
playbackActive = false;
|
playbackObject.pausePlayback();
|
||||||
playbackTimer->stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::btnReverseClick()
|
void FramePlaybackWindow::btnReverseClick()
|
||||||
{
|
{
|
||||||
playbackActive = true;
|
forward = false;
|
||||||
playbackForward = false;
|
playbackObject.startPlaybackBackward();
|
||||||
if (ui->cbOriginalTiming->isChecked())
|
|
||||||
{
|
|
||||||
playbackElapsed.start();
|
|
||||||
playbackTimer->setInterval(1);
|
|
||||||
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp + 2000;
|
|
||||||
}
|
|
||||||
playbackTimer->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::btnStopClick()
|
void FramePlaybackWindow::btnStopClick()
|
||||||
{
|
{
|
||||||
playbackTimer->stop(); //pushing this button halts automatic playback
|
playbackObject.stopPlayback();
|
||||||
playbackActive = false;
|
|
||||||
currentPosition = 0;
|
|
||||||
if (seqItems.count() > 0)
|
if (seqItems.count() > 0)
|
||||||
{
|
{
|
||||||
currentSeqNum = 0;
|
currentSeqNum = 0;
|
||||||
@@ -462,36 +476,29 @@ void FramePlaybackWindow::btnStopClick()
|
|||||||
ui->tblSequence->setCurrentCell(0, 0);
|
ui->tblSequence->setCurrentCell(0, 0);
|
||||||
refreshIDList();
|
refreshIDList();
|
||||||
}
|
}
|
||||||
updateFrameLabel();
|
//updateFrameLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::btnPlayClick()
|
void FramePlaybackWindow::btnPlayClick()
|
||||||
{
|
{
|
||||||
playbackActive = true;
|
forward = true;
|
||||||
playbackForward = true;
|
playbackObject.startPlaybackForward();
|
||||||
if (ui->cbOriginalTiming->isChecked())
|
|
||||||
{
|
|
||||||
playbackTimer->setInterval(1);
|
|
||||||
playbackElapsed.start();
|
|
||||||
if (currentSeqItem->data[currentPosition].timestamp > 1000)
|
|
||||||
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 2000;
|
|
||||||
else playbackLastTimeStamp = 0;
|
|
||||||
}
|
|
||||||
playbackTimer->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::btnFwdOneClick()
|
void FramePlaybackWindow::btnFwdOneClick()
|
||||||
{
|
{
|
||||||
sendingBuffer.clear();
|
forward = true;
|
||||||
playbackTimer->stop();
|
playbackObject.stepPlaybackForward();
|
||||||
playbackActive = false;
|
|
||||||
updatePosition(true);
|
|
||||||
CANConManager::getInstance()->sendFrames(sendingBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::changePlaybackSpeed(int newSpeed)
|
void FramePlaybackWindow::changePlaybackSpeed(int newSpeed)
|
||||||
{
|
{
|
||||||
playbackTimer->setInterval(newSpeed);
|
playbackObject.setPlaybackInterval(newSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramePlaybackWindow::changeBurstRate(int burst)
|
||||||
|
{
|
||||||
|
playbackObject.setPlaybackBurst(burst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::changeLooping(bool check)
|
void FramePlaybackWindow::changeLooping(bool check)
|
||||||
@@ -501,7 +508,7 @@ void FramePlaybackWindow::changeLooping(bool check)
|
|||||||
|
|
||||||
void FramePlaybackWindow::changeSendingBus(int newIdx)
|
void FramePlaybackWindow::changeSendingBus(int newIdx)
|
||||||
{
|
{
|
||||||
whichBusSend = newIdx;
|
calculateWhichBus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::changeIDFiltering(QListWidgetItem *item)
|
void FramePlaybackWindow::changeIDFiltering(QListWidgetItem *item)
|
||||||
@@ -530,185 +537,3 @@ void FramePlaybackWindow::btnSelectNoneClick()
|
|||||||
currentSeqItem->idFilters[Utility::ParseStringToNum(item->text())] = false;
|
currentSeqItem->idFilters[Utility::ParseStringToNum(item->text())] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramePlaybackWindow::timerTriggered()
|
|
||||||
{
|
|
||||||
sendingBuffer.clear();
|
|
||||||
|
|
||||||
if (ui->cbOriginalTiming->isChecked())
|
|
||||||
{
|
|
||||||
//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;
|
|
||||||
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 > 1000)
|
|
||||||
playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp - 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 + 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int count = 0; count < ui->spinBurstSpeed->value(); count++)
|
|
||||||
{
|
|
||||||
if (!playbackActive)
|
|
||||||
{
|
|
||||||
playbackTimer->stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (playbackForward)
|
|
||||||
{
|
|
||||||
updatePosition(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
updatePosition(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CANConManager::getInstance()->sendFrames(sendingBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 FramePlaybackWindow::updatePosition(bool forward)
|
|
||||||
{
|
|
||||||
//qDebug() << "updatePosition";
|
|
||||||
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?
|
|
||||||
{
|
|
||||||
currentSeqNum++; //go forward in the sequence
|
|
||||||
if (currentSeqNum == seqItems.count()) //are we at the end of the sequence?
|
|
||||||
{
|
|
||||||
//reset the loop figures for each sequence entry
|
|
||||||
for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0;
|
|
||||||
currentSeqNum = 0;
|
|
||||||
if (ui->cbLoop->isChecked()) //go back to beginning if we're looping the sequence
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
else //not looping so stop playback entirely
|
|
||||||
{
|
|
||||||
playbackActive = false;
|
|
||||||
playbackTimer->stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentSeqItem = &seqItems[currentSeqNum];
|
|
||||||
ui->tblSequence->setCurrentCell(currentSeqNum, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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?
|
|
||||||
{
|
|
||||||
currentSeqNum--; //go backward in the sequence
|
|
||||||
if (currentSeqNum == -1) //are we trying to go past the beginning?
|
|
||||||
{
|
|
||||||
//reset the loop figures for each sequence entry
|
|
||||||
for (int i = 0; i < seqItems.count(); i++) seqItems[i].currentLoopCount = 0;
|
|
||||||
currentSeqNum = seqItems.count() - 1;
|
|
||||||
if (ui->cbLoop->isChecked()) //go back to the last sequence entry if we're looping
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
else //not looping so stop playback entirely
|
|
||||||
{
|
|
||||||
playbackActive = false;
|
|
||||||
playbackTimer->stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentSeqItem = &seqItems[currentSeqNum];
|
|
||||||
ui->tblSequence->setCurrentCell(currentSeqNum, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateFrameLabel();
|
|
||||||
//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->ID).value())
|
|
||||||
{
|
|
||||||
if (whichBusSend < ui->comboCANBus->count() - 2)
|
|
||||||
{
|
|
||||||
thisFrame->bus = whichBusSend;
|
|
||||||
sendingBuffer.append(*thisFrame);
|
|
||||||
}
|
|
||||||
else if (whichBusSend == (ui->comboCANBus->count() - 2)) //all
|
|
||||||
{
|
|
||||||
for (int c = 0; c < ui->comboCANBus->count() - 2; c++)
|
|
||||||
{
|
|
||||||
thisFrame->bus = c;
|
|
||||||
sendingBuffer.append(*thisFrame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else //from file so retain original bus and send as-is
|
|
||||||
{
|
|
||||||
sendingBuffer.append(*thisFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
thisFrame->bus = originalBus;
|
|
||||||
}
|
|
||||||
return thisFrame->timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 FramePlaybackWindow::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+8
-23
@@ -2,26 +2,15 @@
|
|||||||
#define FRAMEPLAYBACKWINDOW_H
|
#define FRAMEPLAYBACKWINDOW_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QElapsedTimer>
|
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QTimer>
|
|
||||||
#include "can_structs.h"
|
#include "can_structs.h"
|
||||||
#include "framefileio.h"
|
#include "framefileio.h"
|
||||||
|
#include "frameplaybackobject.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class FramePlaybackWindow;
|
class FramePlaybackWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
//one entry in the sequence of data to use
|
|
||||||
struct SequenceItem
|
|
||||||
{
|
|
||||||
QString filename;
|
|
||||||
QVector<CANFrame> data;
|
|
||||||
QHash<int, bool> idFilters;
|
|
||||||
int maxLoops;
|
|
||||||
int currentLoopCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FramePlaybackWindow : public QDialog
|
class FramePlaybackWindow : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -39,12 +28,12 @@ private slots:
|
|||||||
void btnFwdOneClick();
|
void btnFwdOneClick();
|
||||||
void btnDeleteCurrSeq();
|
void btnDeleteCurrSeq();
|
||||||
void changePlaybackSpeed(int newSpeed);
|
void changePlaybackSpeed(int newSpeed);
|
||||||
|
void changeBurstRate(int burst);
|
||||||
void changeLooping(bool check);
|
void changeLooping(bool check);
|
||||||
void changeSendingBus(int newIdx);
|
void changeSendingBus(int newIdx);
|
||||||
void changeIDFiltering(QListWidgetItem *item);
|
void changeIDFiltering(QListWidgetItem *item);
|
||||||
void btnSelectAllClick();
|
void btnSelectAllClick();
|
||||||
void btnSelectNoneClick();
|
void btnSelectNoneClick();
|
||||||
void timerTriggered();
|
|
||||||
void btnLoadFile();
|
void btnLoadFile();
|
||||||
void btnLoadLive();
|
void btnLoadLive();
|
||||||
void seqTableCellClicked(int row, int col);
|
void seqTableCellClicked(int row, int col);
|
||||||
@@ -53,33 +42,29 @@ private slots:
|
|||||||
void saveFilters();
|
void saveFilters();
|
||||||
void loadFilters();
|
void loadFilters();
|
||||||
void useOrigTimingClicked();
|
void useOrigTimingClicked();
|
||||||
|
void getStatusUpdate(int frameNum);
|
||||||
|
void EndOfFrameCache();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::FramePlaybackWindow *ui;
|
Ui::FramePlaybackWindow *ui;
|
||||||
QList<int> foundID;
|
QList<int> foundID;
|
||||||
QList<CANFrame> frameCache;
|
QList<CANFrame> frameCache;
|
||||||
QList<CANFrame> sendingBuffer;
|
|
||||||
const QVector<CANFrame> *modelFrames;
|
const QVector<CANFrame> *modelFrames;
|
||||||
int currentPosition;
|
|
||||||
QTimer *playbackTimer;
|
|
||||||
QElapsedTimer playbackElapsed;
|
|
||||||
quint64 playbackLastTimeStamp;
|
|
||||||
bool playbackActive;
|
|
||||||
bool playbackForward;
|
|
||||||
int whichBusSend;
|
|
||||||
QList<SequenceItem> seqItems;
|
QList<SequenceItem> seqItems;
|
||||||
SequenceItem *currentSeqItem;
|
SequenceItem *currentSeqItem;
|
||||||
int currentSeqNum;
|
int currentSeqNum;
|
||||||
|
FramePlaybackObject playbackObject;
|
||||||
|
bool forward;
|
||||||
|
int currentPosition;
|
||||||
|
|
||||||
void refreshIDList();
|
void refreshIDList();
|
||||||
void updateFrameLabel();
|
void updateFrameLabel();
|
||||||
quint64 updatePosition(bool forward);
|
|
||||||
quint64 peekPosition(bool forward);
|
|
||||||
void fillIDHash(SequenceItem &item);
|
void fillIDHash(SequenceItem &item);
|
||||||
void showEvent(QShowEvent *);
|
void showEvent(QShowEvent *);
|
||||||
void closeEvent(QCloseEvent *event);
|
void closeEvent(QCloseEvent *event);
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
|
void calculateWhichBus();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FRAMEPLAYBACKWINDOW_H
|
#endif // FRAMEPLAYBACKWINDOW_H
|
||||||
|
|||||||
Reference in New Issue
Block a user