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/mqtt_bus.cpp \
|
||||
dbc/dbcnodeduplicateeditor.cpp \
|
||||
framesenderobject.cpp \
|
||||
mqtt/qmqtt_client.cpp \
|
||||
mqtt/qmqtt_client_p.cpp \
|
||||
mqtt/qmqtt_frame.cpp \
|
||||
@@ -113,6 +114,7 @@ HEADERS += mainwindow.h \
|
||||
connections/mqtt_bus.h \
|
||||
dbc/dbcnodeduplicateeditor.h \
|
||||
dbc/dbcnoderebaseeditor.h \
|
||||
framesenderobject.h \
|
||||
mqtt/qmqtt.h \
|
||||
mqtt/qmqtt_client.h \
|
||||
mqtt/qmqtt_client_p.h \
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "can_structs.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QUuid>
|
||||
|
||||
enum TriggerMask
|
||||
{
|
||||
@@ -38,6 +39,7 @@ public:
|
||||
//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.
|
||||
//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
|
||||
{
|
||||
public:
|
||||
@@ -45,6 +47,7 @@ public:
|
||||
int bus;
|
||||
int databyte;
|
||||
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
|
||||
@@ -73,7 +76,8 @@ public:
|
||||
class Modifier
|
||||
{
|
||||
public:
|
||||
int destByte;
|
||||
int destByte; //if -1 then target one of this ID's signals instead
|
||||
QString signalName;
|
||||
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_REM, 50);
|
||||
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_MODS, 220);
|
||||
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_TRIGGER, 270);
|
||||
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_MODS, 270);
|
||||
ui->tableSender->setColumnWidth(ST_COLS::SENDTAB_COL_COUNT, 80);
|
||||
ui->tableSender->setHorizontalHeaderLabels(headers);
|
||||
}
|
||||
@@ -693,6 +693,12 @@ void FrameSenderWindow::processModifierText(int 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&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.
|
||||
//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
|
||||
@@ -710,22 +716,33 @@ void FrameSenderWindow::processModifierText(int line)
|
||||
Modifier thisMod;
|
||||
thisMod.destByte = 0;
|
||||
|
||||
QString leftSide = Utility::grabAlphaNumeric(mods[i]);
|
||||
if (leftSide.startsWith("D") && leftSide.length() == 2)
|
||||
QRegularExpression regex;
|
||||
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();
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Something wrong with lefthand val";
|
||||
continue;
|
||||
}
|
||||
if (!(Utility::grabOperation(mods[i]) == "="))
|
||||
{
|
||||
qDebug() << "Err: No = after lefthand val";
|
||||
continue;
|
||||
QString leftSide = Utility::grabAlphaNumeric(mods[i]);
|
||||
if (leftSide.startsWith("D") && leftSide.length() == 2)
|
||||
{
|
||||
thisMod.destByte = leftSide.right(1).toInt();
|
||||
thisMod.operations.clear();
|
||||
if (!(Utility::grabOperation(mods[i]) == "="))
|
||||
{
|
||||
qDebug() << "Err: No = after lefthand val";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abort = false;
|
||||
|
||||
token = Utility::grabAlphaNumeric(mods[i]);
|
||||
|
||||
+198
@@ -164,6 +164,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
connect(ui->btnExpandAll, &QAbstractButton::clicked, this, &MainWindow::expandAllRows);
|
||||
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"));
|
||||
lbHelp.setText(tr("Press F1 on any screen for help"));
|
||||
lbHelp.setAlignment(Qt::AlignCenter);
|
||||
@@ -227,12 +229,35 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
ui->actionMotorControlConfig->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);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
updateTimer.stop();
|
||||
frameSender->stopSending();
|
||||
killEmAll(); //Ride the lightning
|
||||
delete ui;
|
||||
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)
|
||||
{
|
||||
Q_UNUSED(connectionType);
|
||||
@@ -1371,6 +1564,11 @@ CANFrameModel* MainWindow::getCANFrameModel()
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* All functions past this point set up the various other windows that can be opened
|
||||
*/
|
||||
|
||||
void MainWindow::showSettingsDialog()
|
||||
{
|
||||
if (!settingsDialog)
|
||||
|
||||
+19
-1
@@ -10,7 +10,7 @@
|
||||
#include "framefileio.h"
|
||||
#include "dbc/dbchandler.h"
|
||||
#include "bus_protocols/isotp_handler.h"
|
||||
|
||||
#include "framesenderobject.h"
|
||||
#include "re/graphingwindow.h"
|
||||
#include "re/frameinfowindow.h"
|
||||
#include "frameplaybackwindow.h"
|
||||
@@ -40,6 +40,19 @@ class ConnectionWindow;
|
||||
class ISOTP_InterpreterWindow;
|
||||
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 {
|
||||
class MainWindow;
|
||||
}
|
||||
@@ -114,6 +127,7 @@ private slots:
|
||||
void filterClearAll();
|
||||
void headerClicked (int logicalIndex);
|
||||
void DBCSettingsUpdated();
|
||||
void onSenderCellChanged(int, int);
|
||||
|
||||
public slots:
|
||||
void gotFrames(int);
|
||||
@@ -142,6 +156,7 @@ private:
|
||||
QByteArray inputBuffer;
|
||||
QTimer updateTimer;
|
||||
QElapsedTimer *elapsedTime;
|
||||
FrameSenderObject *frameSender;
|
||||
int framesPerSec;
|
||||
int rxFrames;
|
||||
bool inhibitFilterUpdate;
|
||||
@@ -151,6 +166,7 @@ private:
|
||||
bool CSVAbsTime;
|
||||
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 inhibitSenderChanged;
|
||||
|
||||
bool continuousLogging;
|
||||
int continuousLogFlushCounter;
|
||||
@@ -211,6 +227,8 @@ private:
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
void manageRowExpansion();
|
||||
void disableAutoRowExpansion();
|
||||
void createSenderRow();
|
||||
void processSenderCellChange(int line, int col);
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1008</width>
|
||||
<width>1350</width>
|
||||
<height>611</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
||||
+316
-309
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>682</height>
|
||||
<width>1177</width>
|
||||
<height>717</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -26,340 +26,347 @@
|
||||
<string>SavvyCAN</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="5,1">
|
||||
<item>
|
||||
<widget class="QTableView" name="canFramesView">
|
||||
<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">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="4,1">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblRemoteConn">
|
||||
<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>
|
||||
<widget class="QTableView" name="canFramesView">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
<italic>true</italic>
|
||||
<bold>true</bold>
|
||||
<bold>false</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">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Overwrite Mode</string>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</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">
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnFilterAll">
|
||||
<widget class="QLabel" name="lblRemoteConn">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
<string>Remote Connection Active:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnFilterNone">
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
<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">
|
||||
<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>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableSimpleSender"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
@@ -367,7 +374,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<width>1177</width>
|
||||
<height>26</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
||||
Reference in New Issue
Block a user