diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 7f1d15e..39f0178 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -64,7 +64,8 @@ SOURCES += main.cpp\ bus_protocols/isotp_handler.cpp \ bus_protocols/j1939_handler.cpp \ bus_protocols/uds_handler.cpp \ - jsedit.cpp + jsedit.cpp \ + frameplaybackobject.cpp HEADERS += mainwindow.h \ can_structs.h \ @@ -117,7 +118,8 @@ HEADERS += mainwindow.h \ bus_protocols/j1939_handler.h \ bus_protocols/uds_handler.h \ bus_protocols/isotp_message.h \ - jsedit.h + jsedit.h \ + frameplaybackobject.h FORMS += ui/candatagrid.ui \ ui/connectionwindow.ui \ diff --git a/connections/connectionwindow.cpp b/connections/connectionwindow.cpp index a326a9e..99d084b 100644 --- a/connections/connectionwindow.cpp +++ b/connections/connectionwindow.cpp @@ -90,6 +90,7 @@ void ConnectionWindow::showEvent(QShowEvent* event) readSettings(); ui->tableConnections->selectRow(0); currentRowChanged(ui->tableConnections->currentIndex(), ui->tableConnections->currentIndex()); + handleConnTypeChanged(); } void ConnectionWindow::closeEvent(QCloseEvent *event) diff --git a/frameplaybackobject.cpp b/frameplaybackobject.cpp new file mode 100644 index 0000000..c58c048 --- /dev/null +++ b/frameplaybackobject.cpp @@ -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); +} + + + + + + + diff --git a/frameplaybackobject.h b/frameplaybackobject.h new file mode 100644 index 0000000..0935ffc --- /dev/null +++ b/frameplaybackobject.h @@ -0,0 +1,102 @@ +#ifndef FRAMEPLAYBACKOBJECT_H +#define FRAMEPLAYBACKOBJECT_H + +#include +#include +#include +#include +#include +#include "can_structs.h" +#include "connections/canconmanager.h" + +//one entry in the sequence of data to use +struct SequenceItem +{ + QString filename; + QVector data; + QHash 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 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 diff --git a/frameplaybackwindow.cpp b/frameplaybackwindow.cpp index b0f0eaa..87725ae 100644 --- a/frameplaybackwindow.cpp +++ b/frameplaybackwindow.cpp @@ -32,19 +32,17 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge ui->comboCANBus->addItem(tr("From File")); ui->comboCANBus->setCurrentIndex(0); + playbackObject.initialize(); + playbackObject.setNumBuses(numBuses); + readSettings(); 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; currentSeqNum = -1; + currentPosition = 0; + forward = true; updateFrameLabel(); @@ -58,10 +56,10 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge connect(ui->btnSelectNone, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnSelectNoneClick); connect(ui->btnDelete, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnDeleteCurrSeq); 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->comboCANBus, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSendingBus(int))); 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->btnLoadLive, &QAbstractButton::clicked, this, &FramePlaybackWindow::btnLoadLive); connect(ui->tblSequence, &QTableWidget::cellPressed, this, &FramePlaybackWindow::seqTableCellClicked); @@ -70,10 +68,13 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge connect(ui->btnSaveFilters, &QAbstractButton::clicked, this, &FramePlaybackWindow::saveFilters); 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); 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; headers << "Source" << "Loops"; @@ -86,9 +87,6 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector *frames, QWidge FramePlaybackWindow::~FramePlaybackWindow() { delete ui; - - playbackTimer->stop(); - delete playbackTimer; } void FramePlaybackWindow::showEvent(QShowEvent *) @@ -116,7 +114,8 @@ void FramePlaybackWindow::readSettings() } ui->spinPlaySpeed->setValue(settings.value("Playback/DefSpeed", 5).toInt()); ui->comboCANBus->setCurrentIndex(settings.value("Playback/SendingBus", 0).toInt()); - whichBusSend = ui->comboCANBus->currentIndex(); + + calculateWhichBus(); } void FramePlaybackWindow::writeSettings() @@ -257,6 +256,35 @@ void FramePlaybackWindow::refreshIDList() 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() { int row = currentSeqNum; @@ -320,11 +348,13 @@ void FramePlaybackWindow::useOrigTimingClicked() { ui->spinBurstSpeed->setEnabled(false); ui->spinPlaySpeed->setEnabled(false); + playbackObject.setUseOriginalTiming(true); } else { ui->spinBurstSpeed->setEnabled(true); ui->spinPlaySpeed->setEnabled(true); + playbackObject.setUseOriginalTiming(false); } } @@ -332,11 +362,7 @@ void FramePlaybackWindow::btnDeleteCurrSeq() { if (currentSeqNum == -1) return; - if (playbackActive) - { - playbackActive = false; - playbackTimer->stop(); - } + playbackObject.stopPlayback(); seqItems.removeAt(currentSeqNum); ui->tblSequence->removeRow(currentSeqNum); @@ -380,6 +406,7 @@ void FramePlaybackWindow::btnLoadFile() { currentSeqNum = 0; currentSeqItem = &seqItems[0]; + playbackObject.setSequenceObject(currentSeqItem); } refreshIDList(); updateFrameLabel(); @@ -408,6 +435,7 @@ void FramePlaybackWindow::btnLoadLive() { currentSeqNum = 0; currentSeqItem = &seqItems[0]; + playbackObject.setSequenceObject(currentSeqItem); } refreshIDList(); updateFrameLabel(); @@ -416,38 +444,24 @@ void FramePlaybackWindow::btnLoadLive() void FramePlaybackWindow::btnBackOneClick() { - sendingBuffer.clear(); - playbackTimer->stop(); //pushing this button halts automatic playback - playbackActive = false; - - updatePosition(false); - CANConManager::getInstance()->sendFrames(sendingBuffer); + forward = false; + playbackObject.stepPlaybackBackward(); } void FramePlaybackWindow::btnPauseClick() { - playbackActive = false; - playbackTimer->stop(); + playbackObject.pausePlayback(); } void FramePlaybackWindow::btnReverseClick() { - playbackActive = true; - playbackForward = false; - if (ui->cbOriginalTiming->isChecked()) - { - playbackElapsed.start(); - playbackTimer->setInterval(1); - playbackLastTimeStamp = currentSeqItem->data[currentPosition].timestamp + 2000; - } - playbackTimer->start(); + forward = false; + playbackObject.startPlaybackBackward(); } void FramePlaybackWindow::btnStopClick() { - playbackTimer->stop(); //pushing this button halts automatic playback - playbackActive = false; - currentPosition = 0; + playbackObject.stopPlayback(); if (seqItems.count() > 0) { currentSeqNum = 0; @@ -462,36 +476,29 @@ void FramePlaybackWindow::btnStopClick() ui->tblSequence->setCurrentCell(0, 0); refreshIDList(); } - updateFrameLabel(); + //updateFrameLabel(); } void FramePlaybackWindow::btnPlayClick() { - playbackActive = true; - playbackForward = true; - 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(); + forward = true; + playbackObject.startPlaybackForward(); } void FramePlaybackWindow::btnFwdOneClick() { - sendingBuffer.clear(); - playbackTimer->stop(); - playbackActive = false; - updatePosition(true); - CANConManager::getInstance()->sendFrames(sendingBuffer); + forward = true; + playbackObject.stepPlaybackForward(); } void FramePlaybackWindow::changePlaybackSpeed(int newSpeed) { - playbackTimer->setInterval(newSpeed); + playbackObject.setPlaybackInterval(newSpeed); +} + +void FramePlaybackWindow::changeBurstRate(int burst) +{ + playbackObject.setPlaybackBurst(burst); } void FramePlaybackWindow::changeLooping(bool check) @@ -501,7 +508,7 @@ void FramePlaybackWindow::changeLooping(bool check) void FramePlaybackWindow::changeSendingBus(int newIdx) { - whichBusSend = newIdx; + calculateWhichBus(); } void FramePlaybackWindow::changeIDFiltering(QListWidgetItem *item) @@ -530,185 +537,3 @@ void FramePlaybackWindow::btnSelectNoneClick() 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; -} - diff --git a/frameplaybackwindow.h b/frameplaybackwindow.h index 7de1ac3..f9e163d 100644 --- a/frameplaybackwindow.h +++ b/frameplaybackwindow.h @@ -2,26 +2,15 @@ #define FRAMEPLAYBACKWINDOW_H #include -#include #include -#include #include "can_structs.h" #include "framefileio.h" +#include "frameplaybackobject.h" namespace Ui { class FramePlaybackWindow; } -//one entry in the sequence of data to use -struct SequenceItem -{ - QString filename; - QVector data; - QHash idFilters; - int maxLoops; - int currentLoopCount; -}; - class FramePlaybackWindow : public QDialog { Q_OBJECT @@ -39,12 +28,12 @@ private slots: void btnFwdOneClick(); void btnDeleteCurrSeq(); void changePlaybackSpeed(int newSpeed); + void changeBurstRate(int burst); void changeLooping(bool check); void changeSendingBus(int newIdx); void changeIDFiltering(QListWidgetItem *item); void btnSelectAllClick(); void btnSelectNoneClick(); - void timerTriggered(); void btnLoadFile(); void btnLoadLive(); void seqTableCellClicked(int row, int col); @@ -53,33 +42,29 @@ private slots: void saveFilters(); void loadFilters(); void useOrigTimingClicked(); + void getStatusUpdate(int frameNum); + void EndOfFrameCache(); private: Ui::FramePlaybackWindow *ui; QList foundID; QList frameCache; - QList sendingBuffer; const QVector *modelFrames; - int currentPosition; - QTimer *playbackTimer; - QElapsedTimer playbackElapsed; - quint64 playbackLastTimeStamp; - bool playbackActive; - bool playbackForward; - int whichBusSend; QList seqItems; SequenceItem *currentSeqItem; int currentSeqNum; + FramePlaybackObject playbackObject; + bool forward; + int currentPosition; void refreshIDList(); void updateFrameLabel(); - quint64 updatePosition(bool forward); - quint64 peekPosition(bool forward); void fillIDHash(SequenceItem &item); void showEvent(QShowEvent *); void closeEvent(QCloseEvent *event); void readSettings(); void writeSettings(); + void calculateWhichBus(); }; #endif // FRAMEPLAYBACKWINDOW_H