Addition of the range state window (it sort of works now too!),

refactoring of some DBC code, fixed some DBC calcs, fixed a bug in the
frame playback window, incremented version number to show that a lot
has been done.
This commit is contained in:
Collin Kidder
2015-12-07 21:47:41 -05:00
parent 1e46af88f1
commit 72f07f304f
11 changed files with 742 additions and 98 deletions
+6 -3
View File
@@ -38,7 +38,8 @@ SOURCES += main.cpp\
discretestatewindow.cpp \
scriptingwindow.cpp \
scriptcontainer.cpp \
canfilter.cpp
canfilter.cpp \
rangestatewindow.cpp
HEADERS += mainwindow.h \
can_structs.h \
@@ -66,7 +67,8 @@ HEADERS += mainwindow.h \
discretestatewindow.h \
scriptingwindow.h \
scriptcontainer.h \
canfilter.h
canfilter.h \
rangestatewindow.h
FORMS += mainwindow.ui \
graphingwindow.ui \
@@ -82,7 +84,8 @@ FORMS += mainwindow.ui \
mainsettingsdialog.ui \
firmwareuploaderwindow.ui \
discretestatewindow.ui \
scriptingwindow.ui
scriptingwindow.ui \
rangestatewindow.ui
DISTFILES +=
+2 -2
View File
@@ -1,12 +1,12 @@
#ifndef CONFIG
#define CONFIG
#define VERSION 143
#define VERSION 144
//try to keep this in sync.
//SavvyCAN will complain if you connect a GVRET board with a revision
//less than this number.
#define CURRENT_GVRET_VER 325 //330 is the newest but it is WIP
#define CURRENT_GVRET_VER 331
#endif // CONFIG
+5 -57
View File
@@ -3,6 +3,7 @@
#include <QFile>
#include <QRegularExpression>
#include <QDebug>
#include "utility.h"
DBCHandler::DBCHandler(QObject *parent) : QObject(parent)
{
@@ -538,8 +539,7 @@ QString DBCHandler::processSignal(const CANFrame &frame, const DBC_SIGNAL &sig)
{
int64_t result = 0;
int bit;
int sigSize;
bool isSigned = false;
if (sig.valType == STRING)
{
QString buildString;
@@ -547,62 +547,10 @@ QString DBCHandler::processSignal(const CANFrame &frame, const DBC_SIGNAL &sig)
int bytes = sig.signalSize / 8;
for (int x = 0; x < bytes; x++) buildString.append(frame.data[startByte + x]);
return buildString;
}
}
sigSize = sig.signalSize;
if (sig.intelByteOrder)
{
bit = sig.startBit;
for (int bitpos = 0; bitpos < sigSize; bitpos++)
{
if (frame.data[bit / 8] & (1 << (bit % 8)))
result += (1ULL << bitpos);
bit++;
}
}
else //motorola / big endian mode
{
bit = sig.startBit;
for (int bitpos = 0; bitpos < sigSize; bitpos++)
{
if (frame.data[bit / 8] & (1 << (bit % 8)))
result += (1ULL << (sigSize - bitpos - 1));
if ((bit % 8) == 0)
bit += 15;
else bit--;
}
}
if (sig.valType == SIGNED_INT)
{
int mask = (1 << (sig.signalSize - 1));
if ((result & mask) == mask) //is the highest bit possible for this signal size set?
{
/*
* if so we need to also set every bit higher in the result int too.
* This leads to the below two lines that are nasty. Here's the theory behind that...
* If the value is signed and the highest bit is set then it is negative. To create
* a negative value out of this even though the variable result is 64 bit we have to
* run 1's all of the way up to bit 63 in result. -1 is all ones for whatever size integer
* you have. So, it's 64 1's in this case.
* signedMask is done this way:
* first you take the signal size and shift 1 up that far. Then subtract one. Lets
* see that for a 16 bit signal:
* (1 << 16) - 1 = the first 16 bits set as 1's. So far so good. We then negate the whole
* thing which flips all bits. Thus signedMask ends up with 1's everwhere that the signal
* doesn't take up in the 64 bit signed integer result. Then, result has an OR operation on
* it with the old value and -1 masked so that the the 1 bits from -1 don't overwrite bits from the
* actual signal. This extends the sign bits out so that the integer result reads as the proper negative
* value. We dont need to do any of this if the sign bit wasn't set.
*/
int signedMask = ~((1 << sig.signalSize) - 1);
result = (-1 & signedMask) | result;
}
}
if (sig.valType == SIGNED_INT) isSigned = true;
result = Utility::processIntegerSignal(frame.data, sig.startBit, sig.signalSize, sig.intelByteOrder, isSigned);
double endResult = ((double)result * sig.factor) + sig.bias;
result = (int) endResult;
+2
View File
@@ -388,6 +388,7 @@ void FramePlaybackWindow::btnLoadFile()
currentSeqNum = 0;
currentSeqItem = &seqItems[0];
}
refreshIDList();
updateFrameLabel();
}
}
@@ -416,6 +417,7 @@ void FramePlaybackWindow::btnLoadLive()
currentSeqNum = 0;
currentSeqItem = &seqItems[0];
}
refreshIDList();
updateFrameLabel();
btnStopClick();
}
+47 -36
View File
@@ -110,47 +110,48 @@ MainWindow::MainWindow(QWidget *parent) :
firmwareUploaderWindow = NULL;
discreteStateWindow = NULL;
scriptingWindow = NULL;
rangeWindow = NULL;
dbcHandler = new DBCHandler;
bDirty = false;
inhibitFilterUpdate = false;
model->setDBCHandler(dbcHandler);
connect(ui->btnConnect, SIGNAL(clicked(bool)), this, SLOT(connButtonPress()));
connect(ui->actionOpen_Log_File, SIGNAL(triggered(bool)), this, SLOT(handleLoadFile()));
connect(ui->actionGraph_Dta, SIGNAL(triggered(bool)), this, SLOT(showGraphingWindow()));
connect(ui->actionFrame_Data_Analysis, SIGNAL(triggered(bool)), this, SLOT(showFrameDataAnalysis()));
connect(ui->btnClearFrames, SIGNAL(clicked(bool)), this, SLOT(clearFrames()));
connect(ui->actionSave_Log_File, SIGNAL(triggered(bool)), this, SLOT(handleSaveFile()));
connect(ui->actionSave_Filtered_Log_File, SIGNAL(triggered(bool)), this, SLOT(handleSaveFilteredFile()));
connect(ui->actionLoad_Filter_Definition, SIGNAL(triggered(bool)), this, SLOT(handleLoadFilters()));
connect(ui->actionSave_Filter_Definition, SIGNAL(triggered(bool)), this, SLOT(handleSaveFilters()));
connect(ui->action_Playback, SIGNAL(triggered(bool)), this, SLOT(showPlaybackWindow()));
connect(ui->btnBaudSet, SIGNAL(clicked(bool)), this, SLOT(changeBaudRates()));
connect(ui->actionFlow_View, SIGNAL(triggered(bool)), this, SLOT(showFlowViewWindow()));
connect(ui->action_Custom, SIGNAL(triggered(bool)), this, SLOT(showFrameSenderWindow()));
connect(ui->actionLoad_DBC_File, SIGNAL(triggered(bool)), this, SLOT(handleLoadDBC()));
connect(ui->actionSave_DBC_File, SIGNAL(triggered(bool)), this, SLOT(handleSaveDBC()));
connect(ui->canFramesView, SIGNAL(clicked(QModelIndex)), this, SLOT(gridClicked(QModelIndex)));
connect(ui->canFramesView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(gridDoubleClicked(QModelIndex)));
connect(ui->cbInterpret, SIGNAL(toggled(bool)), this, SLOT(interpretToggled(bool)));
connect(ui->cbOverwrite, SIGNAL(toggled(bool)), this, SLOT(overwriteToggled(bool)));
connect(ui->actionEdit_Messages_Signals, SIGNAL(triggered(bool)), this, SLOT(showDBCEditor()));
connect(ui->btnCaptureToggle, SIGNAL(clicked(bool)), this, SLOT(toggleCapture()));
connect(ui->actionExit_Application, SIGNAL(triggered(bool)), this, SLOT(exitApp()));
connect(ui->actionFuzzy_Scope, SIGNAL(triggered(bool)), this, SLOT(showFuzzyScopeWindow()));
connect(ui->actionRange_State, SIGNAL(triggered(bool)), this, SLOT(showRangeWindow()));
connect(ui->actionSave_Decoded_Frames, SIGNAL(triggered(bool)), this, SLOT(handleSaveDecoded()));
connect(ui->actionSingle_Multi_State, SIGNAL(triggered(bool)), this, SLOT(showSingleMultiWindow()));
connect(ui->actionFile_Comparison, SIGNAL(triggered(bool)), this, SLOT(showComparisonWindow()));
connect(ui->actionScripting_INterface, SIGNAL(triggered(bool)), this, SLOT(showScriptingWindow()));
connect(ui->btnNormalize, SIGNAL(clicked(bool)), this, SLOT(normalizeTiming()));
connect(ui->actionPreferences, SIGNAL(triggered(bool)), this, SLOT(showSettingsDialog()));
connect(model, SIGNAL(updatedFiltersList()), this, SLOT(updateFilterList()));
connect(ui->listFilters, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(filterListItemChanged(QListWidgetItem*)));
connect(ui->btnFilterAll, SIGNAL(clicked(bool)), this, SLOT(filterSetAll()));
connect(ui->btnFilterNone, SIGNAL(clicked(bool)), this, SLOT(filterClearAll()));
connect(ui->actionFirmware_Uploader, SIGNAL(triggered(bool)), this, SLOT(showFirmwareUploaderWindow()));
connect(ui->btnConnect, &QAbstractButton::clicked, this, &MainWindow::connButtonPress);
connect(ui->actionOpen_Log_File, &QAction::triggered, this, &MainWindow::handleLoadFile);
connect(ui->actionGraph_Dta, &QAction::triggered, this, &MainWindow::showGraphingWindow);
connect(ui->actionFrame_Data_Analysis, &QAction::triggered, this, &MainWindow::showFrameDataAnalysis);
connect(ui->btnClearFrames, &QAbstractButton::clicked, this, &MainWindow::clearFrames);
connect(ui->actionSave_Log_File, &QAction::triggered, this, &MainWindow::handleSaveFile);
connect(ui->actionSave_Filtered_Log_File, &QAction::triggered, this, &MainWindow::handleSaveFilteredFile);
connect(ui->actionLoad_Filter_Definition, &QAction::triggered, this, &MainWindow::handleLoadFilters);
connect(ui->actionSave_Filter_Definition, &QAction::triggered, this, &MainWindow::handleSaveFilters);
connect(ui->action_Playback, &QAction::triggered, this, &MainWindow::showPlaybackWindow);
connect(ui->btnBaudSet, &QAbstractButton::clicked, this, &MainWindow::changeBaudRates);
connect(ui->actionFlow_View, &QAction::triggered, this, &MainWindow::showFlowViewWindow);
connect(ui->action_Custom, &QAction::triggered, this, &MainWindow::showFrameSenderWindow);
connect(ui->actionLoad_DBC_File, &QAction::triggered, this, &MainWindow::handleLoadDBC);
connect(ui->actionSave_DBC_File, &QAction::triggered, this, &MainWindow::handleSaveDBC);
connect(ui->canFramesView, &QAbstractItemView::clicked, this, &MainWindow::gridClicked);
connect(ui->canFramesView, &QAbstractItemView::doubleClicked, this, &MainWindow::gridDoubleClicked);
connect(ui->cbInterpret, &QAbstractButton::toggled, this, &MainWindow::interpretToggled);
connect(ui->cbOverwrite, &QAbstractButton::toggled, this, &MainWindow::overwriteToggled);
connect(ui->actionEdit_Messages_Signals, &QAction::triggered, this, &MainWindow::showDBCEditor);
connect(ui->btnCaptureToggle, &QAbstractButton::clicked, this, &MainWindow::toggleCapture);
connect(ui->actionExit_Application, &QAction::triggered, this, &MainWindow::exitApp);
connect(ui->actionFuzzy_Scope, &QAction::triggered, this, &MainWindow::showFuzzyScopeWindow);
connect(ui->actionRange_State_2, &QAction::triggered, this, &MainWindow::showRangeWindow);
connect(ui->actionSave_Decoded_Frames, &QAction::triggered, this, &MainWindow::handleSaveDecoded);
connect(ui->actionSingle_Multi_State_2, &QAction::triggered, this, &MainWindow::showSingleMultiWindow);
connect(ui->actionFile_Comparison, &QAction::triggered, this, &MainWindow::showComparisonWindow);
connect(ui->actionScripting_INterface, &QAction::triggered, this, &MainWindow::showScriptingWindow);
connect(ui->btnNormalize, &QAbstractButton::clicked, this, &MainWindow::normalizeTiming);
connect(ui->actionPreferences, &QAction::triggered, this, &MainWindow::showSettingsDialog);
connect(model, &CANFrameModel::updatedFiltersList, this, &MainWindow::updateFilterList);
connect(ui->listFilters, &QListWidget::itemChanged, this, &MainWindow::filterListItemChanged);
connect(ui->btnFilterAll, &QAbstractButton::clicked, this, &MainWindow::filterSetAll);
connect(ui->btnFilterNone, &QAbstractButton::clicked, this, &MainWindow::filterClearAll);
connect(ui->actionFirmware_Uploader, &QAction::triggered, this, &MainWindow::showFirmwareUploaderWindow);
lbStatusConnected.setText(tr("Not connected"));
updateFileStatus();
@@ -244,6 +245,12 @@ MainWindow::~MainWindow()
delete scriptingWindow;
}
if (rangeWindow)
{
rangeWindow->close();
delete rangeWindow;
}
delete ui;
delete dbcHandler;
model->clearFrames();
@@ -1053,7 +1060,11 @@ void MainWindow::showScriptingWindow()
void MainWindow::showRangeWindow()
{
//not done yet
if (!rangeWindow)
{
rangeWindow = new RangeStateWindow(model->getListReference());
}
rangeWindow->show();
}
void MainWindow::showFuzzyScopeWindow()
+2
View File
@@ -20,6 +20,7 @@
#include "firmwareuploaderwindow.h"
#include "discretestatewindow.h"
#include "scriptingwindow.h"
#include "rangestatewindow.h"
namespace Ui {
class MainWindow;
@@ -124,6 +125,7 @@ private:
DiscreteStateWindow *discreteStateWindow;
FirmwareUploaderWindow *firmwareUploaderWindow;
ScriptingWindow *scriptingWindow;
RangeStateWindow *rangeWindow;
//various private storage
QLabel lbStatusConnected;
+12
View File
@@ -304,6 +304,8 @@
<addaction name="actionGraph_Dta"/>
<addaction name="actionFrame_Data_Analysis"/>
<addaction name="actionFile_Comparison"/>
<addaction name="actionRange_State_2"/>
<addaction name="actionSingle_Multi_State_2"/>
</widget>
<widget class="QMenu" name="menuSend_Frames">
<property name="title">
@@ -448,6 +450,16 @@
<string>Scripting Interface</string>
</property>
</action>
<action name="actionRange_State_2">
<property name="text">
<string>Range State</string>
</property>
</action>
<action name="actionSingle_Multi_State_2">
<property name="text">
<string>Single/Multi State</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
+359
View File
@@ -0,0 +1,359 @@
#include "rangestatewindow.h"
#include "ui_rangestatewindow.h"
#include "mainwindow.h"
#include "utility.h"
RangeStateWindow::RangeStateWindow(const QVector<CANFrame> *frames, QWidget *parent) :
QDialog(parent),
ui(new Ui::RangeStateWindow)
{
ui->setupUi(this);
modelFrames = frames;
ui->graphSignal->xAxis->setRange(0, 8);
ui->graphSignal->yAxis->setRange(-10, 265); //run range a bit outside possible number so they aren't plotted in a hard to see place
ui->graphSignal->xAxis->setVisible(false);
ui->graphSignal->yAxis->setVisible(false);
//ui->graphSignal->axisRect()->setupFullAxesBox();
ui->cbSignalMode->addItem(tr("Big Endian"));
ui->cbSignalMode->addItem(tr("Little Endian"));
ui->cbSignalMode->addItem(tr("Try Both"));
ui->cbSignedMode->addItem(tr("Signed Value"));
ui->cbSignedMode->addItem(tr("Unsigned Value"));
ui->cbSignedMode->addItem(tr("Try Both"));
//lambda expressions used here because these are tiny functions that don't have any reason to be full named functions
//unfortunately the fact that valueChanged is overloaded makes the syntax here HORRIBLE. That sucks.
connect(ui->spinMaxSigSize, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
[=](int newVal)
{
if (newVal < ui->spinMinSigSize->value()) ui->spinMinSigSize->setValue(newVal);
});
connect(ui->spinMinSigSize, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
[=](int newVal)
{
if (newVal > ui->spinMaxSigSize->value()) ui->spinMaxSigSize->setValue(newVal);
});
connect(ui->btnAllFilter, &QAbstractButton::clicked,
[=]()
{
for (int i = 0; i < ui->listFilter->count(); i++)
{
QListWidgetItem *item = ui->listFilter->item(i);
item->setCheckState(Qt::Checked);
idFilters[Utility::ParseStringToNum(item->text())] = true;
}
});
connect(ui->btnNoneFilter, &QAbstractButton::clicked,
[=]()
{
for (int i = 0; i < ui->listFilter->count(); i++)
{
QListWidgetItem *item = ui->listFilter->item(i);
item->setCheckState(Qt::Unchecked);
idFilters[Utility::ParseStringToNum(item->text())] = false;
}
});
connect(ui->listFilter, &QListWidget::itemChanged,
[=](QListWidgetItem *item)
{
bool isChecked = false;
int id = Utility::ParseStringToNum(item->text());
if (item->checkState() == Qt::Checked) isChecked = true;
idFilters[id] = isChecked;
});
connect(ui->btnRecalc, &QAbstractButton::clicked, this, &RangeStateWindow::recalcButton);
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
}
RangeStateWindow::~RangeStateWindow()
{
delete ui;
}
void RangeStateWindow::showEvent(QShowEvent* event)
{
QDialog::showEvent(event);
readSettings();
refreshFilterList();
}
void RangeStateWindow::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
writeSettings();
}
void RangeStateWindow::readSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
resize(settings.value("RangeStateView/WindowSize", QSize(765, 615)).toSize());
move(settings.value("RangeStateView/WindowPos", QPoint(50, 50)).toPoint());
}
}
void RangeStateWindow::writeSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
settings.setValue("RangeStateView/WindowSize", size());
settings.setValue("RangeStateView/WindowPos", pos());
}
}
void RangeStateWindow::updatedFrames(int numFrames)
{
CANFrame thisFrame;
if (numFrames == -1) //all frames deleted. We don't need to do a thing on this window but erase everything in the filters section
{
ui->listFilter->clear();
idFilters.clear();
}
else if (numFrames == -2) //all new set of frames. Reset
{
refreshFilterList();
}
else //just got some new frames. See if we need to update the filters list. Otherwise nothing to do - no recalc happens until the button is pressed
{
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
{
thisFrame = modelFrames->at(i);
if (!idFilters.contains(thisFrame.ID))
{
idFilters.insert(thisFrame.ID, true);
QListWidgetItem* listItem = new QListWidgetItem(Utility::formatNumber(thisFrame.ID), ui->listFilter);
listItem->setFlags(listItem->flags() | Qt::ItemIsUserCheckable); // set checkable flag
listItem->setCheckState(Qt::Checked); //default all filters to be set active
}
}
}
}
void RangeStateWindow::refreshFilterList()
{
int id;
idFilters.clear();
ui->listFilter->clear();
for (int i = 0; i < modelFrames->length(); i++)
{
id = modelFrames->at(i).ID;
if (!idFilters.contains(id))
{
idFilters.insert(id, true);
QListWidgetItem* listItem = new QListWidgetItem(Utility::formatNumber(id), ui->listFilter);
listItem->setFlags(listItem->flags() | Qt::ItemIsUserCheckable); // set checkable flag
listItem->setCheckState(Qt::Checked); //default all filters to be set active
}
}
ui->listFilter->sortItems();
}
void RangeStateWindow::recalcButton()
{
QHash<int, bool>::iterator iter;
int id;
ui->listCandidates->clear();
for (iter = idFilters.begin(); iter != idFilters.end(); ++iter)
{
if (iter.value() == true)
{
qDebug() << "Processing for ID: " << iter.key();
//so, we're supposed to process this frame ID. We'll need to create a frame cache for it
frameCache.clear();
frameCache.reserve(modelFrames->count()); //block allocate more than enough space
id = iter.key();
for (int j = 0; j < modelFrames->count(); j++)
{
if (modelFrames->at(j).ID == id) frameCache.append(modelFrames->at(j));
}
//now we've got a list with all the same ID. Time to send it off for processing
signalsFactory();
}
}
}
/*
* Uses the settings exposed to the user to generate a set of candidate signals that should be checked.
* The user could specify signal sizes, granularity, endian type and we generate all the permutations from there
* Should process from max to min and stop when a valid signal is found (at least as an option) to declutter a bit.
* Mostly what we're interested in is the largest signal that matches
*/
void RangeStateWindow::signalsFactory()
{
int minSig = ui->spinMinSigSize->value();
int maxSig = ui->spinMaxSigSize->value();
int granularity = ui->spinGranularity->value();
int sigType = ui->cbSignalMode->currentIndex() + 1;
int signedType = ui->cbSignedMode->currentIndex() + 1;
int maxBits = frameCache.at(0).len * 8;
int sens = ui->slideSensitivity->value();
for (int sigSize = maxSig; sigSize >= minSig; sigSize--)
{
for (int startBit = 0; startBit < maxBits; startBit += granularity)
{
if (sigType & 1)
{
if (signedType & 1) processSignal(startBit, sigSize, sens, true, true);
if (signedType & 2) processSignal(startBit, sigSize, sens, true, false);
}
if (sigType & 2)
{
if (signedType & 1) processSignal(startBit, sigSize, sens, false, true);
if (signedType & 2) processSignal(startBit, sigSize, sens, false, false);
}
//have to try both types even with 8 bit and smaller signals
//because they could cross byte boundaries. Could check whether they
//do and not try both types if it is impossible.
}
}
}
/*
* Given the signal we generate the relevant data and figure out whether this signal seems to be a smooth range signal
*/
void RangeStateWindow::processSignal(int startBit, int bitLength, int sensitivity, bool bigEndian, bool isSigned)
{
qDebug() << "S:" << startBit << " B:" << bitLength << " X:" << sensitivity << " E:" << bigEndian;
QVector<int> scaledVals;
QVector<int> diff1;
QVector<int> diff2;
int64_t valu;
int64_t highestValue = -1000000000000LL;
int64_t lowestValue = 1000000000000LL;
double multiplier;
int numFrames = frameCache.count();
scaledVals.reserve(frameCache.count());
diff1.reserve(frameCache.count() - 1);
diff2.reserve(frameCache.count() - 2);
int i;
for (i = 0; i < numFrames; i++)
{
valu = Utility::processIntegerSignal(frameCache.at(i).data, startBit, bitLength, !bigEndian, isSigned);
if (valu < lowestValue) lowestValue = valu;
if (valu > highestValue) highestValue = valu;
}
qDebug() << "Min: " << lowestValue << " Max: " << highestValue;
//multiplier is calculated such that the range of the signal is scaled down to the value of sensitivity.
//so, if we have a sensitivity of 50 then the range is scaled so that it is 50
//this has the effect of smoothing the data a bit by completely removing the fine detail. It's irrelevant to
//an algorithm like this anyway and just gets in the way.
//Also, we're going to offset by lowest value so that everything is based at a value of 0 as the low end.
//All of this drastically modifies the actual signal but that's OK, we're looking for patterns here not
//being faithful to the signal (what a dirty cheater)
int range = highestValue - lowestValue;
multiplier = (double)sensitivity / (double)range;
for (i = 0; i < numFrames; i++) scaledVals.append((int)((Utility::processIntegerSignal(frameCache.at(i).data, startBit, bitLength, !bigEndian, isSigned) - lowestValue) * multiplier));
for (i = 1; i < numFrames; i++)
{
valu = scaledVals[i-1] - scaledVals[i];
diff1.append(valu);
}
for (i = 1; i < diff1.count(); i++)
{
valu = diff1[i-1] - diff1[i];
diff2.append(valu);
}
//now the differences are all stored so let's go through and see if they seem to suggest a ramping sort of signal or not.
//for a first test lets let through any signal where the acceleration values are all much smaller than the signal range
bool isGood = true;
int comparisonValue = abs(sensitivity / 10);
qDebug() << "range: " << sensitivity << " comparisonvalue: " << comparisonValue;
int overValues = 0;
for (i = 0; i < diff2.count(); i++)
{
if (abs(diff1[i]) > comparisonValue) overValues++;
}
if (overValues > (numFrames / 5000)) isGood = false;
qDebug() << "Is this signal good: " << isGood << " Num overs: " << overValues;
if (isGood)
{
createGraph(scaledVals);
//qDebug() << "Graphing";
QString temp;
temp = "ID: " + QString::number(frameCache.at(0).ID, 16) + " startBit: " + QString::number(startBit) + " len: " + QString::number(bitLength) + "BigEndian: " + QString::number(bigEndian) + " Signed: " + QString::number(isSigned);
ui->listCandidates->addItem(temp);
}
}
//graphs the vector such that the X axis is just the index into the vector and Y is perfectly graphed within the window
void RangeStateWindow::createGraph(QVector<int> values)
{
int tempVal;
float minval=1000000, maxval = -100000;
int numEntries = values.count();
ui->graphSignal->clearGraphs();
QVector<double> x(numEntries), y(numEntries);
for (int j = 0; j < numEntries; j++)
{
tempVal = values[j];
x[j] = j;
y[j] = tempVal;
if (y[j] < minval) minval = y[j];
if (y[j] > maxval) maxval = y[j];
}
qDebug() << "YMin: " << minval << " YMax: " << maxval;
double ymin, ymax;
ymin = minval;
if (ymin < 0) ymin *= 1.2;
else ymin *= 0.8;
ymax = maxval;
if (ymax < 0) ymax * 0.8;
else ymax *= 1.2;
ui->graphSignal->addGraph();
ui->graphSignal->graph()->setName("Graph");
ui->graphSignal->graph()->setData(x,y);
ui->graphSignal->graph()->setLineStyle(QCPGraph::lsLine); //connect points with lines
QPen graphPen;
graphPen.setColor(Qt::black);
graphPen.setWidth(1);
ui->graphSignal->graph()->setPen(graphPen);
ui->graphSignal->xAxis->setRange(0, numEntries);
ui->graphSignal->yAxis->setRange(ymin, ymax);
ui->graphSignal->replot();
}
+39
View File
@@ -0,0 +1,39 @@
#ifndef RANGESTATEWINDOW_H
#define RANGESTATEWINDOW_H
#include <QDialog>
#include "can_structs.h"
namespace Ui {
class RangeStateWindow;
}
class RangeStateWindow : public QDialog
{
Q_OBJECT
public:
explicit RangeStateWindow(const QVector<CANFrame> *frames, QWidget *parent = 0);
~RangeStateWindow();
void showEvent(QShowEvent*);
private slots:
void updatedFrames(int);
void recalcButton();
private:
Ui::RangeStateWindow *ui;
const QVector<CANFrame> *modelFrames;
QVector<CANFrame> frameCache;
QHash<int, bool> idFilters;
void refreshFilterList();
void closeEvent(QCloseEvent *event);
void readSettings();
void writeSettings();
void signalsFactory();
void processSignal(int startBit, int bitLength, int sensitivity, bool bigEndian, bool isSigned);
void createGraph(QVector<int> values);
};
#endif // RANGESTATEWINDOW_H
+207
View File
@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RangeStateWindow</class>
<widget class="QDialog" name="RangeStateWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>763</width>
<height>938</height>
</rect>
</property>
<property name="windowTitle">
<string>Range State Window</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,2,0,2">
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Candidate Signals:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listCandidates"/>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Graphical Representation of Selected Signal:</string>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="graphSignal" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Sensitivity</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="slideSensitivity">
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>250</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Min Signal Size:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinMinSigSize">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>32</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Max Signal Size:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinMaxSigSize">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>32</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Granularity:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinGranularity">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>32</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Signal Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbSignalMode"/>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Signed Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbSignedMode"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>ID Filter:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listFilter"/>
</item>
<item>
<widget class="QPushButton" name="btnAllFilter">
<property name="text">
<string>All</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnNoneFilter">
<property name="text">
<string>None</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="btnRecalc">
<property name="text">
<string>Recalculate Candidate Signals</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
+61
View File
@@ -113,6 +113,67 @@ public:
{
return (value1 * (1.0 - samplePoint)) + (value2 * samplePoint);
}
static int64_t processIntegerSignal(const uint8_t *data, int startBit, int sigSize, bool littleEndian, bool isSigned)
{
int64_t result = 0;
int bit;
if (littleEndian)
{
bit = startBit;
for (int bitpos = 0; bitpos < sigSize; bitpos++)
{
if (data[bit / 8] & (1 << (bit % 8)))
result += (1ULL << bitpos);
bit++;
}
}
else //motorola / big endian mode
{
bit = startBit;
for (int bitpos = 0; bitpos < sigSize; bitpos++)
{
if (data[bit / 8] & (1 << (bit % 8)))
result += (1ULL << (sigSize - bitpos - 1));
if ((bit % 8) == 0)
bit += 15;
else bit--;
}
}
if (isSigned)
{
int64_t mask = (1ULL << (sigSize - 1));
if ((result & mask) == mask) //is the highest bit possible for this signal size set?
{
/*
* if so we need to also set every bit higher in the result int too.
* This leads to the below two lines that are nasty. Here's the theory behind that...
* If the value is signed and the highest bit is set then it is negative. To create
* a negative value out of this even though the variable result is 64 bit we have to
* run 1's all of the way up to bit 63 in result. -1 is all ones for whatever size integer
* you have. So, it's 64 1's in this case.
* signedMask is done this way:
* first you take the signal size and shift 1 up that far. Then subtract one. Lets
* see that for a 16 bit signal:
* (1 << 16) - 1 = the first 16 bits set as 1's. So far so good. We then negate the whole
* thing which flips all bits. Thus signedMask ends up with 1's everwhere that the signal
* doesn't take up in the 64 bit signed integer result. Then, result has an OR operation on
* it with the old value and -1 masked so that the the 1 bits from -1 don't overwrite bits from the
* actual signal. This extends the sign bits out so that the integer result reads as the proper negative
* value. We dont need to do any of this if the sign bit wasn't set.
*/
int64_t signedMask = ~((1ULL << sigSize) - 1);
result = (-1LL & signedMask) | result;
}
}
return result;
}
};
#endif // UTILITY_H