Partial implementation of a more generic and multi-threaded version of
the frame sender. Now a simplified interface is attached to the main window as well. Doesn't necessarily work just yet...
This commit is contained in:
@@ -26,6 +26,7 @@ SOURCES += main.cpp\
|
|||||||
connections/lawicel_serial.cpp \
|
connections/lawicel_serial.cpp \
|
||||||
connections/mqtt_bus.cpp \
|
connections/mqtt_bus.cpp \
|
||||||
dbc/dbcnodeduplicateeditor.cpp \
|
dbc/dbcnodeduplicateeditor.cpp \
|
||||||
|
framesenderobject.cpp \
|
||||||
mqtt/qmqtt_client.cpp \
|
mqtt/qmqtt_client.cpp \
|
||||||
mqtt/qmqtt_client_p.cpp \
|
mqtt/qmqtt_client_p.cpp \
|
||||||
mqtt/qmqtt_frame.cpp \
|
mqtt/qmqtt_frame.cpp \
|
||||||
@@ -113,6 +114,7 @@ HEADERS += mainwindow.h \
|
|||||||
connections/mqtt_bus.h \
|
connections/mqtt_bus.h \
|
||||||
dbc/dbcnodeduplicateeditor.h \
|
dbc/dbcnodeduplicateeditor.h \
|
||||||
dbc/dbcnoderebaseeditor.h \
|
dbc/dbcnoderebaseeditor.h \
|
||||||
|
framesenderobject.h \
|
||||||
mqtt/qmqtt.h \
|
mqtt/qmqtt.h \
|
||||||
mqtt/qmqtt_client.h \
|
mqtt/qmqtt_client.h \
|
||||||
mqtt/qmqtt_client_p.h \
|
mqtt/qmqtt_client_p.h \
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "can_structs.h"
|
#include "can_structs.h"
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
enum TriggerMask
|
enum TriggerMask
|
||||||
{
|
{
|
||||||
@@ -38,6 +39,7 @@ public:
|
|||||||
//If ID is -1 then this is the temporary storage register. This is a shadow
|
//If ID is -1 then this is the temporary storage register. This is a shadow
|
||||||
//register used to accumulate the results of a multi operation modifier.
|
//register used to accumulate the results of a multi operation modifier.
|
||||||
//if ID is -2 then this is a look up of our own data bytes stored in the class data.
|
//if ID is -2 then this is a look up of our own data bytes stored in the class data.
|
||||||
|
//Of course, if the ID is positive then we grab bytes or signals from newest message with that ID
|
||||||
class ModifierOperand
|
class ModifierOperand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -45,6 +47,7 @@ public:
|
|||||||
int bus;
|
int bus;
|
||||||
int databyte;
|
int databyte;
|
||||||
bool notOper; //should a bitwise NOT be applied to this prior to doing the actual calculation?
|
bool notOper; //should a bitwise NOT be applied to this prior to doing the actual calculation?
|
||||||
|
QString signalName; //if ID is positive and there is text in here then we'll look up the signal and use its value
|
||||||
};
|
};
|
||||||
|
|
||||||
//list of operations that can be done between the two operands
|
//list of operations that can be done between the two operands
|
||||||
@@ -73,7 +76,8 @@ public:
|
|||||||
class Modifier
|
class Modifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int destByte;
|
int destByte; //if -1 then target one of this ID's signals instead
|
||||||
|
QString signalName;
|
||||||
QList<ModifierOp> operations;
|
QList<ModifierOp> operations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,453 @@
|
|||||||
|
#include "framesenderobject.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
FrameSenderObject::FrameSenderObject(const QVector<CANFrame> *frames)
|
||||||
|
{
|
||||||
|
mThread_p = new QThread();
|
||||||
|
|
||||||
|
statusCounter = 0;
|
||||||
|
modelFrames = frames;
|
||||||
|
dbcHandler = DBCHandler::getReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameSenderObject::~FrameSenderObject()
|
||||||
|
{
|
||||||
|
mThread_p->quit();
|
||||||
|
mThread_p->wait();
|
||||||
|
delete mThread_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderObject::piStart()
|
||||||
|
{
|
||||||
|
sendingTimer = new QTimer();
|
||||||
|
sendingTimer->setTimerType(Qt::PreciseTimer);
|
||||||
|
sendingTimer->setInterval(1);
|
||||||
|
|
||||||
|
connect(sendingTimer, &QTimer::timeout, this, &FrameSenderObject::timerTriggered);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderObject::piStop()
|
||||||
|
{
|
||||||
|
sendingTimer->stop();
|
||||||
|
delete sendingTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderObject::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;
|
||||||
|
|
||||||
|
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||||
|
|
||||||
|
/* in multithread case, this will be called before entering thread event loop */
|
||||||
|
return piStart();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderObject::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 FrameSenderObject::startSending()
|
||||||
|
{
|
||||||
|
/* make sure we execute in mThread context */
|
||||||
|
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
|
||||||
|
QMetaObject::invokeMethod(this, "startSending",
|
||||||
|
Qt::BlockingQueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendingElapsed.start();
|
||||||
|
sendingTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderObject::stopSending()
|
||||||
|
{
|
||||||
|
/* make sure we execute in mThread context */
|
||||||
|
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
|
||||||
|
QMetaObject::invokeMethod(this, "stopPlayback",
|
||||||
|
Qt::BlockingQueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendingTimer->stop(); //pushing this button halts automatic playback
|
||||||
|
//emit statusUpdate(currentPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderObject::addSendRecord(FrameSendData record)
|
||||||
|
{
|
||||||
|
/* make sure we execute in mThread context */
|
||||||
|
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
|
||||||
|
QMetaObject::invokeMethod(this, "addSendRecord",
|
||||||
|
Qt::BlockingQueuedConnection,
|
||||||
|
Q_ARG(FrameSendData, record));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendingData.append(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderObject::removeSendRecord(int idx)
|
||||||
|
{
|
||||||
|
/* make sure we execute in mThread context */
|
||||||
|
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
|
||||||
|
QMetaObject::invokeMethod(this, "removeSendRecord",
|
||||||
|
Qt::BlockingQueuedConnection,
|
||||||
|
Q_ARG(int, idx));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendingData.removeAt(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: Getting a reference to an item in a QList is a dangerous thing. If anyone
|
||||||
|
* or anything happens to reallocate the list you're screwed. So, call this, do the
|
||||||
|
* work, and drop the reference as soon as possible.
|
||||||
|
*/
|
||||||
|
FrameSendData *FrameSenderObject::getSendRecordRef(int idx)
|
||||||
|
{
|
||||||
|
if (idx < 0 || idx >= sendingData.count()) return nullptr;
|
||||||
|
return &sendingData[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called every millisecond to set the system update figures and send frames if necessary.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="timerEventArgs"></param>
|
||||||
|
///
|
||||||
|
void FrameSenderObject::timerTriggered()
|
||||||
|
{
|
||||||
|
FrameSendData *sendData;
|
||||||
|
Trigger *trigger;
|
||||||
|
|
||||||
|
sendingList.clear();
|
||||||
|
if(mutex.tryLock())
|
||||||
|
{
|
||||||
|
//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 = sendingElapsed.nsecsElapsed() / 1000;
|
||||||
|
if (elapsed == 0) elapsed = 1;
|
||||||
|
sendingElapsed.start();
|
||||||
|
sendingLastTimeStamp += elapsed;
|
||||||
|
//qDebug() << playbackLastTimeStamp;
|
||||||
|
//qDebug() << "El: " << elapsed;
|
||||||
|
statusCounter++;
|
||||||
|
for (int i = 0; i < sendingData.count(); i++)
|
||||||
|
{
|
||||||
|
sendData = &sendingData[i];
|
||||||
|
if (!sendData->enabled)
|
||||||
|
{
|
||||||
|
if (sendData->triggers.count() > 0)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < sendData->triggers.count(); j++) //resetting currCount when line is disabled
|
||||||
|
{
|
||||||
|
sendData->triggers[j].currCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue; //abort any processing on this if it is not enabled.
|
||||||
|
}
|
||||||
|
if (sendData->triggers.count() == 0)
|
||||||
|
{
|
||||||
|
qDebug() << "No triggers to process";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < sendData->triggers.count(); j++)
|
||||||
|
{
|
||||||
|
trigger = &sendData->triggers[j];
|
||||||
|
if (trigger->currCount >= trigger->maxCount) continue; //don't process if we've sent max frames we were supposed to
|
||||||
|
if (!trigger->readyCount) continue; //don't tick if not ready to tick
|
||||||
|
//is it time to fire?
|
||||||
|
trigger->msCounter += elapsed; //gives proper tracking even if timer doesn't fire as fast as it should
|
||||||
|
if (trigger->msCounter >= trigger->milliseconds)
|
||||||
|
{
|
||||||
|
trigger->msCounter -= trigger->milliseconds;
|
||||||
|
sendData->count++;
|
||||||
|
trigger->currCount++;
|
||||||
|
doModifiers(i);
|
||||||
|
//updateGridRow(i);
|
||||||
|
//qDebug() << "About to try to send a frame";
|
||||||
|
//CANConManager::getInstance()->sendFrame(sendingData[i]);
|
||||||
|
sendingList.append(sendingData[i]); //queue it instead of immediate sending
|
||||||
|
if (trigger->ID > 0) trigger->readyCount = false; //reset flag if this is a timed ID trigger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we have any frames to send after the above then send as a batch
|
||||||
|
if (sendingList.count() > 0) CANConManager::getInstance()->sendFrames(sendingList);
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug() << "framesenderobject::handleTick() couldn't get mutex, elapsed is: " << sendingElapsed.elapsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderObject::buildFrameCache()
|
||||||
|
{
|
||||||
|
CANFrame thisFrame;
|
||||||
|
frameCache.clear();
|
||||||
|
for (int i = 0; i < modelFrames->count(); i++)
|
||||||
|
{
|
||||||
|
thisFrame = modelFrames->at(i);
|
||||||
|
if (!frameCache.contains(thisFrame.frameId()))
|
||||||
|
{
|
||||||
|
frameCache.insert(thisFrame.frameId(), thisFrame);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frameCache[thisFrame.frameId()] = thisFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//remember, negative numbers are special -1 = all frames deleted, -2 = totally new set of frames.
|
||||||
|
void FrameSenderObject::updatedFrames(int numFrames)
|
||||||
|
{
|
||||||
|
CANFrame thisFrame;
|
||||||
|
if (numFrames == -1) //all frames deleted.
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (numFrames == -2) //all new set of frames.
|
||||||
|
{
|
||||||
|
buildFrameCache();
|
||||||
|
}
|
||||||
|
else //just got some new frames. See if they are relevant.
|
||||||
|
{
|
||||||
|
if (numFrames > modelFrames->count()) return;
|
||||||
|
qDebug() << "New frames in sender window";
|
||||||
|
//run through the supposedly new frames in order
|
||||||
|
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||||
|
{
|
||||||
|
thisFrame = modelFrames->at(i);
|
||||||
|
if (!frameCache.contains(thisFrame.frameId()))
|
||||||
|
{
|
||||||
|
frameCache.insert(thisFrame.frameId(), thisFrame);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frameCache[thisFrame.frameId()] = thisFrame;
|
||||||
|
}
|
||||||
|
processIncomingFrame(&thisFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameSenderObject::processIncomingFrame(CANFrame *frame)
|
||||||
|
{
|
||||||
|
for (int sd = 0; sd < sendingData.count(); sd++)
|
||||||
|
{
|
||||||
|
if (sendingData[sd].triggers.count() == 0) continue;
|
||||||
|
bool passedChecks = true;
|
||||||
|
for (int trig = 0; trig < sendingData[sd].triggers.count(); trig++)
|
||||||
|
{
|
||||||
|
Trigger *thisTrigger = &sendingData[sd].triggers[trig];
|
||||||
|
//need to ensure that this trigger is actually related to frames incoming.
|
||||||
|
//Otherwise ignore it here. Only frames that have BUS and/or ID set as trigger will work here.
|
||||||
|
if (!(thisTrigger->triggerMask & (TriggerMask::TRG_BUS | TriggerMask::TRG_ID) ) ) continue;
|
||||||
|
|
||||||
|
passedChecks = true;
|
||||||
|
//qDebug() << "Trigger ID: " << thisTrigger->ID;
|
||||||
|
//qDebug() << "Frame ID: " << frame->frameId();
|
||||||
|
|
||||||
|
//Check to see if we have a bus trigger condition and if so does it match
|
||||||
|
if (thisTrigger->bus != frame->bus && (thisTrigger->triggerMask & TriggerMask::TRG_BUS) )
|
||||||
|
passedChecks = false;
|
||||||
|
|
||||||
|
//check to see if we have an ID trigger condition and if so does it match
|
||||||
|
if ((thisTrigger->triggerMask & TriggerMask::TRG_ID) && (uint32_t)thisTrigger->ID != frame->frameId() )
|
||||||
|
passedChecks = false;
|
||||||
|
|
||||||
|
//check to see if we're limiting the trigger by max count and have we reached that count?
|
||||||
|
if ( (thisTrigger->triggerMask & TriggerMask::TRG_COUNT) && (thisTrigger->currCount >= thisTrigger->maxCount) )
|
||||||
|
passedChecks = false;
|
||||||
|
|
||||||
|
//if the above passed then are we triggering not only on ID but also signal?
|
||||||
|
if (passedChecks && (thisTrigger->triggerMask & (TriggerMask::TRG_SIGNAL | TriggerMask::TRG_ID) ) )
|
||||||
|
{
|
||||||
|
bool sigCheckPassed = false;
|
||||||
|
DBC_MESSAGE *msg = dbcHandler->findMessage(thisTrigger->ID);
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
DBC_SIGNAL *sig = msg->sigHandler->findSignalByName(thisTrigger->sigName);
|
||||||
|
if (sig)
|
||||||
|
{
|
||||||
|
//first of all, is this signal really in this message we got?
|
||||||
|
if (sig->isSignalInMessage(*frame)) sigCheckPassed = true;
|
||||||
|
//if it was and we're also filtering on value then try that next
|
||||||
|
if (sigCheckPassed && (thisTrigger->triggerMask & TriggerMask::TRG_SIGVAL))
|
||||||
|
{
|
||||||
|
double sigval = 0.0;
|
||||||
|
if (sig->processAsDouble(*frame, sigval))
|
||||||
|
{
|
||||||
|
if (abs(sigval - thisTrigger->sigValueDbl) > 0.001)
|
||||||
|
{
|
||||||
|
sigCheckPassed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else sigCheckPassed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else sigCheckPassed = false;
|
||||||
|
}
|
||||||
|
else sigCheckPassed = false;
|
||||||
|
passedChecks &= sigCheckPassed; //passedChecks can only be true if both are
|
||||||
|
}
|
||||||
|
|
||||||
|
//if all the above says it's OK then we'll go ahead and send that message.
|
||||||
|
//If a message that comes through here has a MS value then we use it as a delay
|
||||||
|
//after the check passes. This allows for delaying the sending of the frame if that
|
||||||
|
//is required. Otherwise, just send it immediately.
|
||||||
|
if (passedChecks)
|
||||||
|
{
|
||||||
|
if (thisTrigger->milliseconds == 0) //immediate reply
|
||||||
|
{
|
||||||
|
thisTrigger->currCount++;
|
||||||
|
sendingData[sd].count++;
|
||||||
|
doModifiers(sd);
|
||||||
|
//updateGridRow(sd);
|
||||||
|
CANConManager::getInstance()->sendFrame(sendingData[sd]);
|
||||||
|
}
|
||||||
|
else //delayed sending frame
|
||||||
|
{
|
||||||
|
thisTrigger->readyCount = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// given an index into the sendingData list we run the modifiers that it has set up
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idx">The index into the sendingData list</param>
|
||||||
|
void FrameSenderObject::doModifiers(int idx)
|
||||||
|
{
|
||||||
|
int shadowReg = 0; //shadow register we use to accumulate results
|
||||||
|
int first=0, second=0;
|
||||||
|
|
||||||
|
FrameSendData *sendData = &sendingData[idx];
|
||||||
|
Modifier *mod;
|
||||||
|
ModifierOp op;
|
||||||
|
|
||||||
|
if (sendData->modifiers.count() == 0) return; //if no modifiers just leave right now
|
||||||
|
|
||||||
|
//qDebug() << "Executing mods";
|
||||||
|
|
||||||
|
for (int i = 0; i < sendData->modifiers.count(); i++)
|
||||||
|
{
|
||||||
|
mod = &sendData->modifiers[i];
|
||||||
|
for (int j = 0; j < mod->operations.count(); j++)
|
||||||
|
{
|
||||||
|
op = mod->operations.at(j);
|
||||||
|
if (op.first.ID == -1)
|
||||||
|
{
|
||||||
|
first = shadowReg;
|
||||||
|
}
|
||||||
|
else first = fetchOperand(idx, op.first);
|
||||||
|
second = fetchOperand(idx, op.second);
|
||||||
|
switch (op.operation)
|
||||||
|
{
|
||||||
|
case ADDITION:
|
||||||
|
shadowReg = first + second;
|
||||||
|
break;
|
||||||
|
case AND:
|
||||||
|
shadowReg = first & second;
|
||||||
|
break;
|
||||||
|
case DIVISION:
|
||||||
|
shadowReg = first / second;
|
||||||
|
break;
|
||||||
|
case MULTIPLICATION:
|
||||||
|
shadowReg = first * second;
|
||||||
|
break;
|
||||||
|
case OR:
|
||||||
|
shadowReg = first | second;
|
||||||
|
break;
|
||||||
|
case SUBTRACTION:
|
||||||
|
shadowReg = first - second;
|
||||||
|
break;
|
||||||
|
case XOR:
|
||||||
|
shadowReg = first ^ second;
|
||||||
|
break;
|
||||||
|
case MOD:
|
||||||
|
shadowReg = first % second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Finally, drop the result into the proper data byte
|
||||||
|
QByteArray newArr(sendData->payload());
|
||||||
|
newArr[mod->destByte] = (char) shadowReg;
|
||||||
|
sendData->setPayload(newArr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int FrameSenderObject::fetchOperand(int idx, ModifierOperand op)
|
||||||
|
{
|
||||||
|
CANFrame *tempFrame = nullptr;
|
||||||
|
if (op.ID == 0) //numeric constant
|
||||||
|
{
|
||||||
|
if (op.notOper) return ~op.databyte;
|
||||||
|
else return op.databyte;
|
||||||
|
}
|
||||||
|
else if (op.ID == -2) //fetch data from a data byte within the output frame
|
||||||
|
{
|
||||||
|
if (op.notOper) return ~((unsigned char)sendingData.at(idx).payload()[op.databyte]);
|
||||||
|
else return (unsigned char)sendingData.at(idx).payload()[op.databyte];
|
||||||
|
}
|
||||||
|
else //look up external data byte
|
||||||
|
{
|
||||||
|
tempFrame = lookupFrame(op.ID, op.bus);
|
||||||
|
if (tempFrame != nullptr)
|
||||||
|
{
|
||||||
|
if (op.notOper) return ~((unsigned char)tempFrame->payload()[op.databyte]);
|
||||||
|
else return (unsigned char)tempFrame->payload()[op.databyte];
|
||||||
|
}
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try to find the most recent frame given the input criteria
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ID">The ID to find</param>
|
||||||
|
/// <param name="bus">Which bus to look on (-1 if you don't care)</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
CANFrame* FrameSenderObject::lookupFrame(int ID, int bus)
|
||||||
|
{
|
||||||
|
if (!frameCache.contains(ID)) return nullptr;
|
||||||
|
|
||||||
|
if (bus == -1 || frameCache[ID].bus == bus) return &frameCache[ID];
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#ifndef FRAMESENDEROBJECT_H
|
||||||
|
#define FRAMESENDEROBJECT_H
|
||||||
|
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QMutex>
|
||||||
|
#include "can_structs.h"
|
||||||
|
#include "connections/canconmanager.h"
|
||||||
|
#include "can_trigger_structs.h"
|
||||||
|
#include "dbc/dbchandler.h"
|
||||||
|
|
||||||
|
class FrameSenderObject : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrameSenderObject(const QVector<CANFrame> *frames);
|
||||||
|
~FrameSenderObject();
|
||||||
|
|
||||||
|
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 startSending();
|
||||||
|
void stopSending();
|
||||||
|
|
||||||
|
void addSendRecord(FrameSendData record);
|
||||||
|
void removeSendRecord(int idx);
|
||||||
|
FrameSendData *getSendRecordRef(int idx);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void timerTriggered();
|
||||||
|
void updatedFrames(int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<CANFrame> sendingList;
|
||||||
|
int currentPosition;
|
||||||
|
QTimer *sendingTimer;
|
||||||
|
QElapsedTimer sendingElapsed;
|
||||||
|
quint64 sendingLastTimeStamp;
|
||||||
|
int statusCounter;
|
||||||
|
QList<FrameSendData> sendingData;
|
||||||
|
QThread* mThread_p;
|
||||||
|
QHash<int, CANFrame> frameCache; //hash with frame ID as the key and the most recent frame as the value
|
||||||
|
const QVector<CANFrame> *modelFrames;
|
||||||
|
bool inhibitChanged = false;
|
||||||
|
QMutex mutex;
|
||||||
|
DBCHandler *dbcHandler;
|
||||||
|
|
||||||
|
void doModifiers(int);
|
||||||
|
int fetchOperand(int, ModifierOperand);
|
||||||
|
CANFrame* lookupFrame(int, int);
|
||||||
|
void buildFrameCache();
|
||||||
|
void processIncomingFrame(CANFrame *frame);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief starts the device
|
||||||
|
*/
|
||||||
|
void piStart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief stops the device
|
||||||
|
*/
|
||||||
|
void piStop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FRAMESENDEROBJECT_H
|
||||||
+29
-12
@@ -63,8 +63,8 @@ void FrameSenderWindow::setupGrid()
|
|||||||
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_EXT, 50);
|
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_EXT, 50);
|
||||||
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_REM, 50);
|
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_REM, 50);
|
||||||
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_DATA, 220);
|
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_DATA, 220);
|
||||||
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_TRIGGER, 220);
|
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_TRIGGER, 270);
|
||||||
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_MODS, 220);
|
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_MODS, 270);
|
||||||
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_COUNT, 80);
|
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_COUNT, 80);
|
||||||
ui->tableSender->setHorizontalHeaderLabels(headers);
|
ui->tableSender->setHorizontalHeaderLabels(headers);
|
||||||
}
|
}
|
||||||
@@ -693,6 +693,12 @@ void FrameSenderWindow::processModifierText(int line)
|
|||||||
//Example line:
|
//Example line:
|
||||||
//d0 = D0 + 1,d1 = id:0x200:d3 + id:0x200:d4 AND 0xF0 - Original version
|
//d0 = D0 + 1,d1 = id:0x200:d3 + id:0x200:d4 AND 0xF0 - Original version
|
||||||
//D0=D0+1,D1=ID:0x200:D3+ID:0x200:D4&0xF0
|
//D0=D0+1,D1=ID:0x200:D3+ID:0x200:D4&0xF0
|
||||||
|
|
||||||
|
//[BMS_TargetVoltage]=45 would set the value of signal BMS_TargetVoltage to 45
|
||||||
|
|
||||||
|
//[BMS_TargetVoltage]=[0x234:BMS_CurrentVoltage] + 4 would instead grab the value
|
||||||
|
//of BMS_CurrentVoltage from ID 0x234, add 4 to it, and set BMS_TargetVoltage to that value.
|
||||||
|
|
||||||
//This is certainly much harder to parse than the trigger definitions.
|
//This is certainly much harder to parse than the trigger definitions.
|
||||||
//the left side of the = has to be D0 to D7. After that there is a string of
|
//the left side of the = has to be D0 to D7. After that there is a string of
|
||||||
//data. Spaces used to be required but no longer are. This makes parsing harder but data entry easier
|
//data. Spaces used to be required but no longer are. This makes parsing harder but data entry easier
|
||||||
@@ -710,22 +716,33 @@ void FrameSenderWindow::processModifierText(int line)
|
|||||||
Modifier thisMod;
|
Modifier thisMod;
|
||||||
thisMod.destByte = 0;
|
thisMod.destByte = 0;
|
||||||
|
|
||||||
QString leftSide = Utility::grabAlphaNumeric(mods[i]);
|
QRegularExpression regex;
|
||||||
if (leftSide.startsWith("D") && leftSide.length() == 2)
|
QRegularExpressionMatch match;
|
||||||
|
|
||||||
|
regex.setPattern("^\\[(\\w+)]=(\\w+)");
|
||||||
|
match = regex.match(mods[i]);
|
||||||
|
if (match.hasMatch())
|
||||||
{
|
{
|
||||||
thisMod.destByte = leftSide.right(1).toInt();
|
thisMod.destByte = -1;
|
||||||
|
thisMod.signalName = match.captured(1);
|
||||||
|
mods[i] = match.captured(2);
|
||||||
thisMod.operations.clear();
|
thisMod.operations.clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "Something wrong with lefthand val";
|
QString leftSide = Utility::grabAlphaNumeric(mods[i]);
|
||||||
continue;
|
if (leftSide.startsWith("D") && leftSide.length() == 2)
|
||||||
}
|
{
|
||||||
if (!(Utility::grabOperation(mods[i]) == "="))
|
thisMod.destByte = leftSide.right(1).toInt();
|
||||||
{
|
thisMod.operations.clear();
|
||||||
qDebug() << "Err: No = after lefthand val";
|
if (!(Utility::grabOperation(mods[i]) == "="))
|
||||||
continue;
|
{
|
||||||
|
qDebug() << "Err: No = after lefthand val";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abort = false;
|
abort = false;
|
||||||
|
|
||||||
token = Utility::grabAlphaNumeric(mods[i]);
|
token = Utility::grabAlphaNumeric(mods[i]);
|
||||||
|
|||||||
+198
@@ -164,6 +164,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
connect(ui->btnExpandAll, &QAbstractButton::clicked, this, &MainWindow::expandAllRows);
|
connect(ui->btnExpandAll, &QAbstractButton::clicked, this, &MainWindow::expandAllRows);
|
||||||
connect(ui->btnCollapseAll, &QAbstractButton::clicked, this, &MainWindow::collapseAllRows);
|
connect(ui->btnCollapseAll, &QAbstractButton::clicked, this, &MainWindow::collapseAllRows);
|
||||||
|
|
||||||
|
connect(ui->tableSimpleSender, SIGNAL(cellChanged(int,int)), this, SLOT(onSenderCellChanged(int,int)));
|
||||||
|
|
||||||
lbStatusConnected.setText(tr("Connected to 0 buses"));
|
lbStatusConnected.setText(tr("Connected to 0 buses"));
|
||||||
lbHelp.setText(tr("Press F1 on any screen for help"));
|
lbHelp.setText(tr("Press F1 on any screen for help"));
|
||||||
lbHelp.setAlignment(Qt::AlignCenter);
|
lbHelp.setAlignment(Qt::AlignCenter);
|
||||||
@@ -227,12 +229,35 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
ui->actionMotorControlConfig->setVisible(false);
|
ui->actionMotorControlConfig->setVisible(false);
|
||||||
ui->actionSingle_Multi_State_2->setVisible(false);
|
ui->actionSingle_Multi_State_2->setVisible(false);
|
||||||
|
|
||||||
|
QStringList headers;
|
||||||
|
headers << "En" << "Bus" << "ID" << "Len" << "Ext" << "Rem" << "Data"
|
||||||
|
<< "Interval" << "Count";
|
||||||
|
ui->tableSimpleSender->setColumnCount(9);
|
||||||
|
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_EN, 70);
|
||||||
|
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_BUS, 70);
|
||||||
|
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_ID, 70);
|
||||||
|
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_LEN, 70);
|
||||||
|
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_EXT, 70);
|
||||||
|
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_REM, 70);
|
||||||
|
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_DATA, 300);
|
||||||
|
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_INTERVAL, 100);
|
||||||
|
ui->tableSimpleSender->setColumnWidth(SIMP_COL::SC_COL_COUNT, 100);
|
||||||
|
ui->tableSimpleSender->setHorizontalHeaderLabels(headers);
|
||||||
|
|
||||||
|
createSenderRow();
|
||||||
|
|
||||||
|
frameSender = new FrameSenderObject(model->getListReference());
|
||||||
|
|
||||||
|
frameSender->initialize(); //creates the thread and sets things up
|
||||||
|
frameSender->startSending(); //start the timer in the object so enabled things can send
|
||||||
|
|
||||||
installEventFilter(this);
|
installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
{
|
{
|
||||||
updateTimer.stop();
|
updateTimer.stop();
|
||||||
|
frameSender->stopSending();
|
||||||
killEmAll(); //Ride the lightning
|
killEmAll(); //Ride the lightning
|
||||||
delete ui;
|
delete ui;
|
||||||
delete model;
|
delete model;
|
||||||
@@ -438,6 +463,174 @@ void MainWindow::writeSettings()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::onSenderCellChanged(int row, int col)
|
||||||
|
{
|
||||||
|
if (inhibitSenderChanged) return;
|
||||||
|
qDebug() << "onCellChanged";
|
||||||
|
if (row == ui->tableSimpleSender->rowCount() - 1)
|
||||||
|
{
|
||||||
|
createSenderRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
processSenderCellChange(row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::processSenderCellChange(int line, int col)
|
||||||
|
{
|
||||||
|
qDebug() << "processSenderCellChange";
|
||||||
|
FrameSendData *tempData;
|
||||||
|
QStringList tokens;
|
||||||
|
int tempVal;
|
||||||
|
|
||||||
|
int numBuses = CANConManager::getInstance()->getNumBuses();
|
||||||
|
QByteArray arr;
|
||||||
|
|
||||||
|
tempData = frameSender->getSendRecordRef(line);
|
||||||
|
|
||||||
|
if (!tempData)
|
||||||
|
{
|
||||||
|
FrameSendData dat;
|
||||||
|
frameSender->addSendRecord(dat);
|
||||||
|
tempData = frameSender->getSendRecordRef(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tempData)
|
||||||
|
{
|
||||||
|
qDebug() << "No data to modify in processSenderCellChange. This is a bug!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (col)
|
||||||
|
{
|
||||||
|
case SIMP_COL::SC_COL_EN: //Enable check box
|
||||||
|
if (ui->tableSimpleSender->item(line, 0)->checkState() == Qt::Checked)
|
||||||
|
{
|
||||||
|
tempData->enabled = true;
|
||||||
|
}
|
||||||
|
else tempData->enabled = false;
|
||||||
|
qDebug() << "Setting enabled to " << tempData->enabled;
|
||||||
|
break;
|
||||||
|
case SIMP_COL::SC_COL_BUS: //Bus designation
|
||||||
|
tempVal = Utility::ParseStringToNum(ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_BUS)->text());
|
||||||
|
if (tempVal < -1) tempVal = -1;
|
||||||
|
if (tempVal >= numBuses) tempVal = numBuses - 1;
|
||||||
|
tempData->bus = tempVal;
|
||||||
|
qDebug() << "Setting bus to " << tempVal;
|
||||||
|
break;
|
||||||
|
case SIMP_COL::SC_COL_ID: //ID field
|
||||||
|
tempVal = Utility::ParseStringToNum(ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_ID)->text());
|
||||||
|
if (tempVal < 0) tempVal = 0;
|
||||||
|
if (tempVal > 0x7FFFFFFF) tempVal = 0x7FFFFFFF;
|
||||||
|
tempData->setFrameId(tempVal);
|
||||||
|
if (tempData->frameId() > 0x7FF) {
|
||||||
|
tempData->setExtendedFrameFormat(true);
|
||||||
|
ui->tableSimpleSender->blockSignals(true);
|
||||||
|
ui->tableSimpleSender->item(line, ST_COLS::SENDTAB_COL_EXT)->setCheckState(Qt::Checked);
|
||||||
|
ui->tableSimpleSender->blockSignals(false);
|
||||||
|
}
|
||||||
|
qDebug() << "setting ID to " << tempVal;
|
||||||
|
break;
|
||||||
|
case SIMP_COL::SC_COL_LEN:
|
||||||
|
tempVal = Utility::ParseStringToNum(ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_LEN)->text());
|
||||||
|
if (tempVal < 0) tempVal = 0;
|
||||||
|
if (tempVal > 8) tempVal = 8;
|
||||||
|
arr.resize(tempVal);
|
||||||
|
tempData->setPayload(arr);
|
||||||
|
break;
|
||||||
|
case SIMP_COL::SC_COL_EXT:
|
||||||
|
if (ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_EXT)->checkState() == Qt::Checked) {
|
||||||
|
tempData->setExtendedFrameFormat(true);
|
||||||
|
} else {
|
||||||
|
tempData->setExtendedFrameFormat(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SIMP_COL::SC_COL_REM:
|
||||||
|
if (ui->tableSimpleSender->item(line, SIMP_COL::SC_COL_REM)->checkState() == Qt::Checked) {
|
||||||
|
tempData->setFrameType(QCanBusFrame::RemoteRequestFrame);
|
||||||
|
} else {
|
||||||
|
tempData->setFrameType(QCanBusFrame::DataFrame);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SIMP_COL::SC_COL_DATA: //Data bytes
|
||||||
|
for (int i = 0; i < 8; i++) tempData->payload().data()[i] = 0;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK( 5, 14, 0 )
|
||||||
|
tokens = ui->tableSimpleSender->item(line, ST_COLS::SENDTAB_COL_DATA)->text().split(" ", Qt::SkipEmptyParts);
|
||||||
|
#else
|
||||||
|
tokens = ui->tableSender->item(line, ST_COLS::SENDTAB_COL_DATA)->text().split(" ", QString::SkipEmptyParts);
|
||||||
|
#endif
|
||||||
|
arr.clear();
|
||||||
|
arr.reserve(tokens.count());
|
||||||
|
for (int j = 0; j < tokens.count(); j++)
|
||||||
|
{
|
||||||
|
arr.append((uint8_t)Utility::ParseStringToNum(tokens[j]));
|
||||||
|
}
|
||||||
|
tempData->setPayload(arr);
|
||||||
|
break;
|
||||||
|
case SIMP_COL::SC_COL_INTERVAL: //interval in ms
|
||||||
|
|
||||||
|
QString trigger = ui->tableSimpleSender->item(line, ST_COLS::SENDTAB_COL_TRIGGER)->text().toUpper();
|
||||||
|
|
||||||
|
Trigger thisTrigger;
|
||||||
|
thisTrigger.bus = -1; //-1 means we don't care which
|
||||||
|
thisTrigger.ID = -1; //the rest of these being -1 means nothing has changed it
|
||||||
|
thisTrigger.maxCount = -1;
|
||||||
|
thisTrigger.milliseconds = -1;
|
||||||
|
thisTrigger.currCount = 0;
|
||||||
|
thisTrigger.msCounter = 0;
|
||||||
|
thisTrigger.triggerMask = 0;
|
||||||
|
thisTrigger.readyCount = true;
|
||||||
|
|
||||||
|
tempData->triggers.clear();
|
||||||
|
tempData->triggers.reserve(1);
|
||||||
|
|
||||||
|
if (trigger != "")
|
||||||
|
{
|
||||||
|
thisTrigger.milliseconds = Utility::ParseStringToNum(trigger);
|
||||||
|
thisTrigger.triggerMask |= TriggerMask::TRG_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thisTrigger.milliseconds < 1) thisTrigger.milliseconds = 1;
|
||||||
|
|
||||||
|
tempData->triggers.append(thisTrigger);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::createSenderRow()
|
||||||
|
{
|
||||||
|
int row = ui->tableSimpleSender->rowCount();
|
||||||
|
ui->tableSimpleSender->insertRow(row);
|
||||||
|
|
||||||
|
QTableWidgetItem *item = new QTableWidgetItem();
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
inhibitSenderChanged = true;
|
||||||
|
ui->tableSimpleSender->setItem(row, SIMP_COL::SC_COL_EN, item);
|
||||||
|
|
||||||
|
item = new QTableWidgetItem();
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
ui->tableSimpleSender->setItem(row, SIMP_COL::SC_COL_EXT, item);
|
||||||
|
|
||||||
|
item = new QTableWidgetItem();
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
ui->tableSimpleSender->setItem(row, SIMP_COL::SC_COL_REM, item);
|
||||||
|
|
||||||
|
for (int i = 1; i <= SIMP_COL::SC_COL_COUNT; i++)
|
||||||
|
{
|
||||||
|
if (i != SIMP_COL::SC_COL_EXT && i != SIMP_COL::SC_COL_REM) {
|
||||||
|
item = new QTableWidgetItem("");
|
||||||
|
ui->tableSimpleSender->setItem(row, i, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inhibitSenderChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1)
|
void MainWindow::updateConnectionSettings(QString connectionType, QString port, int speed0, int speed1)
|
||||||
{
|
{
|
||||||
Q_UNUSED(connectionType);
|
Q_UNUSED(connectionType);
|
||||||
@@ -1371,6 +1564,11 @@ CANFrameModel* MainWindow::getCANFrameModel()
|
|||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All functions past this point set up the various other windows that can be opened
|
||||||
|
*/
|
||||||
|
|
||||||
void MainWindow::showSettingsDialog()
|
void MainWindow::showSettingsDialog()
|
||||||
{
|
{
|
||||||
if (!settingsDialog)
|
if (!settingsDialog)
|
||||||
|
|||||||
+19
-1
@@ -10,7 +10,7 @@
|
|||||||
#include "framefileio.h"
|
#include "framefileio.h"
|
||||||
#include "dbc/dbchandler.h"
|
#include "dbc/dbchandler.h"
|
||||||
#include "bus_protocols/isotp_handler.h"
|
#include "bus_protocols/isotp_handler.h"
|
||||||
|
#include "framesenderobject.h"
|
||||||
#include "re/graphingwindow.h"
|
#include "re/graphingwindow.h"
|
||||||
#include "re/frameinfowindow.h"
|
#include "re/frameinfowindow.h"
|
||||||
#include "frameplaybackwindow.h"
|
#include "frameplaybackwindow.h"
|
||||||
@@ -40,6 +40,19 @@ class ConnectionWindow;
|
|||||||
class ISOTP_InterpreterWindow;
|
class ISOTP_InterpreterWindow;
|
||||||
class ScriptingWindow;
|
class ScriptingWindow;
|
||||||
|
|
||||||
|
enum SIMP_COL
|
||||||
|
{
|
||||||
|
SC_COL_EN = 0,
|
||||||
|
SC_COL_BUS = 1,
|
||||||
|
SC_COL_ID = 2,
|
||||||
|
SC_COL_LEN = 3,
|
||||||
|
SC_COL_EXT = 4,
|
||||||
|
SC_COL_REM = 5,
|
||||||
|
SC_COL_DATA = 6,
|
||||||
|
SC_COL_INTERVAL = 7,
|
||||||
|
SC_COL_COUNT = 8,
|
||||||
|
};
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
}
|
}
|
||||||
@@ -114,6 +127,7 @@ private slots:
|
|||||||
void filterClearAll();
|
void filterClearAll();
|
||||||
void headerClicked (int logicalIndex);
|
void headerClicked (int logicalIndex);
|
||||||
void DBCSettingsUpdated();
|
void DBCSettingsUpdated();
|
||||||
|
void onSenderCellChanged(int, int);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void gotFrames(int);
|
void gotFrames(int);
|
||||||
@@ -142,6 +156,7 @@ private:
|
|||||||
QByteArray inputBuffer;
|
QByteArray inputBuffer;
|
||||||
QTimer updateTimer;
|
QTimer updateTimer;
|
||||||
QElapsedTimer *elapsedTime;
|
QElapsedTimer *elapsedTime;
|
||||||
|
FrameSenderObject *frameSender;
|
||||||
int framesPerSec;
|
int framesPerSec;
|
||||||
int rxFrames;
|
int rxFrames;
|
||||||
bool inhibitFilterUpdate;
|
bool inhibitFilterUpdate;
|
||||||
@@ -151,6 +166,7 @@ private:
|
|||||||
bool CSVAbsTime;
|
bool CSVAbsTime;
|
||||||
bool bDirty; //have frames been added or subtracted since the last save/load?
|
bool bDirty; //have frames been added or subtracted since the last save/load?
|
||||||
bool useFiltered; //should sub-windows use the unfiltered or filtered frames list?
|
bool useFiltered; //should sub-windows use the unfiltered or filtered frames list?
|
||||||
|
bool inhibitSenderChanged;
|
||||||
|
|
||||||
bool continuousLogging;
|
bool continuousLogging;
|
||||||
int continuousLogFlushCounter;
|
int continuousLogFlushCounter;
|
||||||
@@ -211,6 +227,8 @@ private:
|
|||||||
bool eventFilter(QObject *obj, QEvent *event);
|
bool eventFilter(QObject *obj, QEvent *event);
|
||||||
void manageRowExpansion();
|
void manageRowExpansion();
|
||||||
void disableAutoRowExpansion();
|
void disableAutoRowExpansion();
|
||||||
|
void createSenderRow();
|
||||||
|
void processSenderCellChange(int line, int col);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1008</width>
|
<width>1350</width>
|
||||||
<height>611</height>
|
<height>611</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
|||||||
+316
-309
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>1177</width>
|
||||||
<height>682</height>
|
<height>717</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@@ -26,340 +26,347 @@
|
|||||||
<string>SavvyCAN</string>
|
<string>SavvyCAN</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralWidget">
|
<widget class="QWidget" name="centralWidget">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
|
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="5,1">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTableView" name="canFramesView">
|
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="4,1">
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<pointsize>11</pointsize>
|
|
||||||
<bold>false</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="verticalScrollMode">
|
|
||||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="lblRemoteConn">
|
<widget class="QTableView" name="canFramesView">
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Remote Connection Active:</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="lineRemoteKey">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>1000</width>
|
|
||||||
<height>50</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="baseSize">
|
|
||||||
<size>
|
|
||||||
<width>150</width>
|
|
||||||
<height>50</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<bold>false</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="maxLength">
|
|
||||||
<number>8</number>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
<property name="readOnly">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="lblContMsg">
|
|
||||||
<property name="palette">
|
|
||||||
<palette>
|
|
||||||
<active>
|
|
||||||
<colorrole role="WindowText">
|
|
||||||
<brush brushstyle="SolidPattern">
|
|
||||||
<color alpha="255">
|
|
||||||
<red>255</red>
|
|
||||||
<green>0</green>
|
|
||||||
<blue>0</blue>
|
|
||||||
</color>
|
|
||||||
</brush>
|
|
||||||
</colorrole>
|
|
||||||
</active>
|
|
||||||
<inactive>
|
|
||||||
<colorrole role="WindowText">
|
|
||||||
<brush brushstyle="SolidPattern">
|
|
||||||
<color alpha="255">
|
|
||||||
<red>255</red>
|
|
||||||
<green>0</green>
|
|
||||||
<blue>0</blue>
|
|
||||||
</color>
|
|
||||||
</brush>
|
|
||||||
</colorrole>
|
|
||||||
</inactive>
|
|
||||||
<disabled>
|
|
||||||
<colorrole role="WindowText">
|
|
||||||
<brush brushstyle="SolidPattern">
|
|
||||||
<color alpha="255">
|
|
||||||
<red>120</red>
|
|
||||||
<green>120</green>
|
|
||||||
<blue>120</blue>
|
|
||||||
</color>
|
|
||||||
</brush>
|
|
||||||
</colorrole>
|
|
||||||
</disabled>
|
|
||||||
</palette>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<pointsize>11</pointsize>
|
<pointsize>11</pointsize>
|
||||||
<italic>true</italic>
|
<bold>false</bold>
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="alternatingRowColors">
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item alignment="Qt::AlignHCenter">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Total Frames Captured:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item alignment="Qt::AlignHCenter">
|
|
||||||
<widget class="QLabel" name="lbNumFrames">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item alignment="Qt::AlignHCenter">
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Frames Per Second:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item alignment="Qt::AlignHCenter">
|
|
||||||
<widget class="QLabel" name="lbFPS">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btnCaptureToggle">
|
|
||||||
<property name="text">
|
|
||||||
<string>Suspend Capturing</string>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btnNormalize">
|
|
||||||
<property name="text">
|
|
||||||
<string>Normalize Frame Timing</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btnClearFrames">
|
|
||||||
<property name="text">
|
|
||||||
<string>Clear Frames</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="cbPersistentFilters">
|
|
||||||
<property name="text">
|
|
||||||
<string>Keep Filters When Clearing</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="cbAutoScroll">
|
|
||||||
<property name="text">
|
|
||||||
<string>Auto Scroll Window</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="cbOverwrite">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="verticalScrollMode">
|
||||||
<string>Overwrite Mode</string>
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="wordWrap">
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="Line" name="line">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="cbInterpret">
|
|
||||||
<property name="text">
|
|
||||||
<string>Interpret Frames</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btnExpandAll">
|
|
||||||
<property name="text">
|
|
||||||
<string>Expand All Rows</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btnCollapseAll">
|
|
||||||
<property name="text">
|
|
||||||
<string>Collapse All Rows</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Bus Filtering:</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QListWidget" name="listBusFilters">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>175</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="flow">
|
|
||||||
<enum>QListView::LeftToRight</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_7">
|
|
||||||
<property name="text">
|
|
||||||
<string>Frame Filtering:</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QListWidget" name="listFilters">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>160</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>175</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btnFilterAll">
|
<widget class="QLabel" name="lblRemoteConn">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>All</string>
|
<string>Remote Connection Active:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btnFilterNone">
|
<widget class="QLineEdit" name="lineRemoteKey">
|
||||||
<property name="text">
|
<property name="enabled">
|
||||||
<string>None</string>
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>1000</width>
|
||||||
|
<height>50</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="baseSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>50</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="maxLength">
|
||||||
|
<number>8</number>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblContMsg">
|
||||||
|
<property name="palette">
|
||||||
|
<palette>
|
||||||
|
<active>
|
||||||
|
<colorrole role="WindowText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>0</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</active>
|
||||||
|
<inactive>
|
||||||
|
<colorrole role="WindowText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>255</red>
|
||||||
|
<green>0</green>
|
||||||
|
<blue>0</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</inactive>
|
||||||
|
<disabled>
|
||||||
|
<colorrole role="WindowText">
|
||||||
|
<brush brushstyle="SolidPattern">
|
||||||
|
<color alpha="255">
|
||||||
|
<red>120</red>
|
||||||
|
<green>120</green>
|
||||||
|
<blue>120</blue>
|
||||||
|
</color>
|
||||||
|
</brush>
|
||||||
|
</colorrole>
|
||||||
|
</disabled>
|
||||||
|
</palette>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>11</pointsize>
|
||||||
|
<italic>true</italic>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Total Frames Captured:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QLabel" name="lbNumFrames">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Frames Per Second:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QLabel" name="lbFPS">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnCaptureToggle">
|
||||||
|
<property name="text">
|
||||||
|
<string>Suspend Capturing</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnNormalize">
|
||||||
|
<property name="text">
|
||||||
|
<string>Normalize Frame Timing</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnClearFrames">
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear Frames</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbPersistentFilters">
|
||||||
|
<property name="text">
|
||||||
|
<string>Keep Filters When Clearing</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbAutoScroll">
|
||||||
|
<property name="text">
|
||||||
|
<string>Auto Scroll Window</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbOverwrite">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Overwrite Mode</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbInterpret">
|
||||||
|
<property name="text">
|
||||||
|
<string>Interpret Frames</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnExpandAll">
|
||||||
|
<property name="text">
|
||||||
|
<string>Expand All Rows</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnCollapseAll">
|
||||||
|
<property name="text">
|
||||||
|
<string>Collapse All Rows</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Bus Filtering:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listBusFilters">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>175</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="flow">
|
||||||
|
<enum>QListView::LeftToRight</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Frame Filtering:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listFilters">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>160</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>175</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnFilterAll">
|
||||||
|
<property name="text">
|
||||||
|
<string>All</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnFilterNone">
|
||||||
|
<property name="text">
|
||||||
|
<string>None</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="tableSimpleSender"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenuBar" name="menuBar">
|
<widget class="QMenuBar" name="menuBar">
|
||||||
@@ -367,7 +374,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>1177</width>
|
||||||
<height>26</height>
|
<height>26</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
|||||||
Reference in New Issue
Block a user