From 7550d047058dd99300de433ba63c5cb4e2a43c1e Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Wed, 23 Aug 2017 21:05:39 -0400 Subject: [PATCH 1/2] Graph Window - fix graph stride, actually works now, added follow mode Follow mode allows you to set a window size and then have the window follow as data comes in. This is handy in order to see a realtime graph of the last "N" seconds of data coming from the CAN bus. --- re/graphingwindow.cpp | 58 ++++++++++++++++++++++++++++++++++--------- re/graphingwindow.h | 3 +++ 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/re/graphingwindow.cpp b/re/graphingwindow.cpp index 8dbfdcd..9db8534 100644 --- a/re/graphingwindow.cpp +++ b/re/graphingwindow.cpp @@ -71,6 +71,7 @@ GraphingWindow::GraphingWindow(const QVector *frames, QWidget *parent) ui->graphingView->setOpenGl(true); //purdy and fast drawing courtesy of your video card - pretty everyone has 3D accel these days needScaleSetup = true; + followGraphEnd = false; } GraphingWindow::~GraphingWindow() @@ -164,6 +165,22 @@ void GraphingWindow::updatedFrames(int numFrames) { graphParams[j].ref->setData(graphParams[j].x, graphParams[j].y); } + if (followGraphEnd) + { + //find the current X span and maintain that span but move the end of it over to match the new end + //of the actual graph. This causes the view to move with the data to always show the end + QCPRange range = ui->graphingView->xAxis->range(); + double size = range.size(); + bool foundRange; + QCPRange keyRange = ui->graphingView->graph()->getKeyRange(foundRange); + if (foundRange) + { + double end, start; + end = keyRange.upper; + start = end - size; + ui->graphingView->xAxis->setRange(start, end); + } + } ui->graphingView->replot(); } } @@ -493,6 +510,11 @@ void GraphingWindow::removeAllGraphs() } } +void GraphingWindow::toggleFollowMode() +{ + followGraphEnd = !followGraphEnd; +} + void GraphingWindow::contextMenuRequest(QPoint pos) { QMenu *menu = new QMenu(this); @@ -512,6 +534,9 @@ void GraphingWindow::contextMenuRequest(QPoint pos) menu->addAction(tr("Save graph definitions to file"), this, SLOT(saveDefinitions())); menu->addAction(tr("Load graph definitions from file"), this, SLOT(loadDefinitions())); menu->addAction(tr("Save spreadsheet of data"), this, SLOT(saveSpreadsheet())); + QAction *act = menu->addAction(tr("Follow end of graph"), this, SLOT(toggleFollowMode())); + act->setCheckable(true); + act->setChecked(followGraphEnd); menu->addAction(tr("Add new graph"), this, SLOT(addNewGraph())); if (ui->graphingView->selectedGraphs().size() > 0) { @@ -953,17 +978,25 @@ void GraphingWindow::addNewGraph() void GraphingWindow::appendToGraph(GraphParams ¶ms, CANFrame &frame) { - int64_t tempVal; //64 bit temp value. - tempVal = Utility::processIntegerSignal(frame.data, params.startBit, params.numBits, params.intelFormat, params.isSigned); //& params.mask; - if (secondsMode) + params.strideSoFar++; + if (params.strideSoFar >= params.stride) { - params.x.append((double)(frame.timestamp) / 1000000.0 - params.xbias); + params.strideSoFar = 0; + int64_t tempVal; //64 bit temp value. + tempVal = Utility::processIntegerSignal(frame.data, params.startBit, params.numBits, params.intelFormat, params.isSigned); //& params.mask; + double xVal, yVal; + if (secondsMode) + { + xVal = ((double)(frame.timestamp) / 1000000.0 - params.xbias); + } + else + { + xVal = (frame.timestamp - params.xbias); + } + yVal = (tempVal * params.scale) + params.bias; + params.x.append(xVal); + params.y.append(yVal); } - else - { - params.x.append(frame.timestamp - params.xbias); - } - params.y.append((tempVal * params.scale) + params.bias); } void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam) @@ -1003,15 +1036,16 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam) for (int j = 0; j < numEntries; j++) { - tempVal = Utility::processIntegerSignal(frameCache[j * params.stride].data, sBit, bits, intelFormat, isSigned); //& params.mask; + int k = j * params.stride; + tempVal = Utility::processIntegerSignal(frameCache[k].data, sBit, bits, intelFormat, isSigned); //& params.mask; //qDebug() << tempVal; if (secondsMode) { - params.x[j] = (double)(frameCache[j].timestamp) / 1000000.0; + params.x[j] = (double)(frameCache[k].timestamp) / 1000000.0; } else { - params.x[j] = frameCache[j].timestamp; + params.x[j] = frameCache[k].timestamp; } params.y[j] = (tempVal * params.scale) + params.bias; if (params.y[j] < yminval) yminval = params.y[j]; diff --git a/re/graphingwindow.h b/re/graphingwindow.h index 08920c7..1294e62 100644 --- a/re/graphingwindow.h +++ b/re/graphingwindow.h @@ -22,6 +22,7 @@ public: float bias; float scale; int stride; + int strideSoFar; QColor color; QCPGraph *ref; QString graphName; @@ -56,6 +57,7 @@ private slots: void saveSpreadsheet(); void saveDefinitions(); void loadDefinitions(); + void toggleFollowMode(); void addNewGraph(); void createGraph(GraphParams ¶ms, bool createGraphParam = true); void appendToGraph(GraphParams ¶ms, CANFrame &frame); @@ -79,6 +81,7 @@ private: QCPSelectionDecorator *selDecorator; bool needScaleSetup; //do we need to set x,y graphing extents? bool secondsMode; + bool followGraphEnd; void showParamsDialog(int idx); void closeEvent(QCloseEvent *event); From bfd0439a692c86d64ec91257a4aa077ab9e6183b Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Wed, 23 Aug 2017 21:51:28 -0400 Subject: [PATCH 2/2] Fixed bugs related to scripting and UDS, implemented more scripting functionality for ISOTP and UDS --- bus_protocols/uds_handler.cpp | 2 ++ scriptcontainer.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp index 5eb5174..9d2a147 100644 --- a/bus_protocols/uds_handler.cpp +++ b/bus_protocols/uds_handler.cpp @@ -169,12 +169,14 @@ void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE msg) } else return; udsMsg.data = msg.data.mid(2, -1); //don't copy error byte nor service byte + udsMsg.len -= 2; //and remove those bytes from the length reported too. } else { udsMsg.isErrorReply = false; if (msg.data.length() > 1) udsMsg.subFunc = msg.data.at(1); udsMsg.data = msg.data.mid(1, -1); //don't copy service byte + udsMsg.len -= 1; //and remove service byte from length too. } } else return; diff --git a/scriptcontainer.cpp b/scriptcontainer.cpp index b429c6d..4867497 100644 --- a/scriptcontainer.cpp +++ b/scriptcontainer.cpp @@ -49,6 +49,8 @@ void ScriptContainer::compileScript() //Find out which callbacks the script has created. setupFunction = scriptEngine.globalObject().property("setup"); canHelper->setRxCallback(scriptEngine.globalObject().property("gotCANFrame")); + isoHelper->setRxCallback(scriptEngine.globalObject().property("gotISOTPMessage")); + udsHelper->setRxCallback(scriptEngine.globalObject().property("gotUDSMessage")); tickFunction = scriptEngine.globalObject().property("tick"); @@ -245,6 +247,7 @@ void ISOTPScriptHelper::setRxCallback(QJSValue cb) void ISOTPScriptHelper::newISOMessage(ISOTP_MESSAGE msg) { + qDebug() << "isotpScriptHelper got a ISOTP message"; if (!gotFrameFunction.isCallable()) return; //nothing to do if we can't even call the function //qDebug() << "Got frame in script interface"; @@ -318,6 +321,8 @@ void UDSScriptHelper::setRxCallback(QJSValue cb) void UDSScriptHelper::newUDSMessage(UDS_MESSAGE msg) { + //qDebug() << "udsScriptHelper got a UDS message"; + qDebug() << "UDS script helper. Meg data len: " << msg.len; if (!gotFrameFunction.isCallable()) return; //nothing to do if we can't even call the function //qDebug() << "Got frame in script interface"; @@ -325,7 +330,7 @@ void UDSScriptHelper::newUDSMessage(UDS_MESSAGE msg) args << msg.bus << msg.ID << msg.service << msg.subFunc << msg.len; QJSValue dataBytes = scriptEngine->newArray(msg.len); - for (unsigned int j = 0; j < msg.len; j++) dataBytes.setProperty(j, QJSValue(msg.data[j])); + for (unsigned int j = 0; j < msg.data.length(); j++) dataBytes.setProperty(j, QJSValue(msg.data[j])); args.append(dataBytes); gotFrameFunction.call(args); }