diff --git a/candatagrid.cpp b/candatagrid.cpp index dff5487..11e8a8e 100644 --- a/candatagrid.cpp +++ b/candatagrid.cpp @@ -69,9 +69,11 @@ void CANDataGrid::paintEvent(QPaintEvent *event) //the next left most column has "0 1 2 3 4 5 6 7" written down along the grid painter.setPen(QPen(Qt::black)); - QFont theFont; - theFont.setPixelSize(qMin(xSector, ySector) - 10); - painter.setFont(theFont); + QFont mainFont; + mainFont.setPixelSize(qMin(xSector, ySector) - 10); + painter.setFont(mainFont); + QFont smallFont; + smallFont.setPixelSize(qMin(xSector, ySector) - 15); painter.drawText(QRect(viewport.left(), viewport.top(), xSpan, ySector), Qt::AlignCenter, tr("BITS")); @@ -95,6 +97,9 @@ void CANDataGrid::paintEvent(QPaintEvent *event) //bits that used to be set but now are unset are red, bits that used to be unset but now are set //are green + painter.setPen(QPen(Qt::gray)); + //painter.setFont(smallFont); + for (y = 0; y < 8; y++) { thisByte = data[y]; @@ -131,6 +136,7 @@ void CANDataGrid::paintEvent(QPaintEvent *event) //painter.fillRect(viewport.left() + (x+2) * xSector, viewport.top() + (y+2) * ySector, xSector, ySector, redBrush); painter.drawRect(viewport.left() + (x+2) * xSector, viewport.top() + (y+2) * ySector, xSector, ySector); + painter.drawText(viewport.left() + (x+2) * xSector + (xSector / 3), viewport.top() + (y + 3) * ySector - (ySector / 3), QString::number(y * 8 + (7-x))); } } upperLeft.setX(viewport.left() + 2 * xSector); diff --git a/config.h b/config.h index 78ef3db..b2ee918 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 136 +#define VERSION 137 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/dbchandler.cpp b/dbchandler.cpp index d757f25..1abeaa2 100644 --- a/dbchandler.cpp +++ b/dbchandler.cpp @@ -87,12 +87,12 @@ void DBCHandler::loadDBCFile(QString filename) } switch (val) { - case 0: - sig.intelByteOrder = true; - break; - case 1: + case 0: //big endian mode sig.intelByteOrder = false; break; + case 1: //little endian mode + sig.intelByteOrder = true; + break; case 2: sig.valType = SP_FLOAT; break; @@ -344,12 +344,12 @@ void DBCHandler::saveDBCFile(QString filename) switch (sig.valType) { case UNSIGNED_INT: - if (sig.intelByteOrder) msgOutput.append("0+"); - else msgOutput.append("1+"); + if (sig.intelByteOrder) msgOutput.append("1+"); + else msgOutput.append("0+"); break; case SIGNED_INT: - if (sig.intelByteOrder) msgOutput.append("0-"); - else msgOutput.append("1-"); + if (sig.intelByteOrder) msgOutput.append("1-"); + else msgOutput.append("0-"); break; case SP_FLOAT: msgOutput.append("2-"); @@ -502,85 +502,77 @@ void DBCHandler::listDebugging() } -//Vector uses a special format for bit ordering. It pretends that the bits are numbered -//0 to 63 in ascending order of bits as if a 64 bit integer were stored lowest first -//and highest bit last. -//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Vector bit ordering -//7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 Normal bitwise ordering within bytes -//0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 Reversed bit order used by Vector -//0 1 2 3 Byte ordering (same either way) -//A 16 bit integer would be stored Low first high second for intel format and high first, low second for motorola +/* + The way that the DBC file format works is kind of weird... For intel format signals you count up +from the start bit to the end bit which is (startbit + signallength - 1). At each point +bits are numbered in a sawtooth manner. What that means is that the very first bit is 0 and you count up +from there all of the way to 63 with each byte being 8 bits so bit 0 is the lowest bit in the first byte +and 8 is the lowest bit in the next byte up. The whole thing looks like this: + Bits + 7 6 5 4 3 2 1 0 + + 0 7 6 5 4 3 2 1 0 +b 1 15 14 13 12 11 10 9 8 +y 2 23 22 21 20 19 18 17 16 +t 3 31 30 29 28 27 26 25 24 +e 4 39 38 37 36 35 34 33 32 +s 5 47 46 45 44 43 42 41 40 + 6 55 54 53 52 51 50 49 48 + 7 63 62 61 60 59 58 57 56 + + For intel format you start at the start bit and keep counting up. If you have a signal size of 8 + and start at bit 12 then the bits are 12, 13, 14, 15, 16, 17, 18, 19 which spans across two bytes. + In this format each bit is worth twice as much as the last and you just keep counting up. + Bit 12 is worth 1, 13 is worth 2, 14 is worth 4, etc all of the way to bit 19 is worth 128. + + Motorola format turns most everything on its head. You count backward from the start bit but + only within the current byte. If you are about to exit the current byte you go one higher and then keep + going backward as before. Using the same example as for intel, start bit of 12 and a signal length of 8. + So, the bits are 12, 11, 10, 9, 8, 23, 22, 21. Yes, that's confusing. They now go in reverse value order too. + Bit 12 is worth 128, 11 is worth 64, etc until bit 21 is worth 1. +*/ -//For intel format invert the starting bit within a byte. -//Otherwise, iterate over the bytes that it encompasses -//For intel format this works nicely as it means you can just go through the list getting higher and higher -//values for each bit as you go. -//For motorola it is backwards but only partially. For each byte you can go through and it's higher as you go -//but, at each byte boundary the next byte is lower than the multiplier for the last. QString DBCHandler::processSignal(const CANFrame &frame, const DBC_SIGNAL &sig) { - int startBit, endBit, startByte, endByte, bitWithinByteStart, bitWithinByteEnd; - int result = 0; - int multiplier; - int bitsToGo; - - startBit = sig.startBit; - startByte = startBit / 8; - bitWithinByteStart = startBit % 8; - if (!sig.intelByteOrder) - { - bitWithinByteStart = 7 - bitWithinByteStart; - startBit = (startByte * 8) + bitWithinByteStart; - } + int64_t result = 0; + int bit; + int sigSize; if (sig.valType == STRING) { QString buildString; + int startByte = sig.signalSize / 8; int bytes = sig.signalSize / 8; for (int x = 0; x < bytes; x++) buildString.append(frame.data[startByte + x]); return buildString; } - endBit = startBit + sig.signalSize - 1; - endByte = endBit / 8; - bitWithinByteEnd = endBit % 8; - bitsToGo = sig.signalSize - 1; + sigSize = sig.signalSize; - multiplier = 1; - if (!sig.intelByteOrder) + if (sig.intelByteOrder) { - for (int y = startByte; y < endByte; y++) multiplier *= 256; + bit = sig.startBit; + for (int bitpos = 0; bitpos < sigSize; bitpos++) + { + if (frame.data[bit / 8] & (1 << (bit % 8))) + result += (1ULL << bitpos); + + bit++; + } } - - //qDebug() << "Signal Name: " << sig.name; - //qDebug() << "Intel Order: " << sig.intelByteOrder; - //qDebug() << "start byte: " << startByte; - //qDebug() << "End Byte: " << endByte; - - int sBit, eBit; - sBit = bitWithinByteStart; - eBit = sBit + bitsToGo; - if (eBit > 7) eBit = 7; - bitsToGo -= (eBit - sBit + 1); - for (int b = startByte; b <= endByte; b++) + else //motorola / big endian mode { - //qDebug() << "Byte: " << frame.data[b]; - //qDebug() << "S: " << sBit; - //qDebug() << "E: " << eBit; - //process this byte - result += processByte(frame.data[b], sBit, eBit) * multiplier; + bit = sig.startBit; + for (int bitpos = 0; bitpos < sigSize; bitpos++) + { + if (frame.data[bit / 8] & (1 << (bit % 8))) + result += (1ULL << (sigSize - bitpos - 1)); - //add to multiplier - if (sig.intelByteOrder) - multiplier = multiplier << 8; - else - multiplier = multiplier >> 8; + if ((bit % 8) == 0) + bit += 15; + else bit--; - //Prepare sBit and eBit for next byte - sBit = 0; //fresh byte so we start at the beginning now - eBit = sBit + bitsToGo; - if (eBit > 7) eBit = 7; - bitsToGo -= (eBit - sBit + 1); + } } if (sig.valType == SIGNED_INT) @@ -613,8 +605,6 @@ QString DBCHandler::processSignal(const CANFrame &frame, const DBC_SIGNAL &sig) double endResult = ((double)result * sig.factor) + sig.bias; result = (int) endResult; - //qDebug() << "Result: " << result; - QString outputString; outputString = sig.name + ": "; diff --git a/dbcsignaleditor.cpp b/dbcsignaleditor.cpp index 7008da8..40d4d09 100644 --- a/dbcsignaleditor.cpp +++ b/dbcsignaleditor.cpp @@ -345,33 +345,41 @@ void DBCSignalEditor::fillSignalForm(DBC_SIGNAL *sig) ui->txtUnitName->setText(sig->unitName); memset(bitpattern, 0, 8); //clear it out first. - int startBit, endBit, startByte, bitWithinByteStart; + + int startBit, endBit; startBit = sig->startBit; - startByte = startBit / 8; - bitWithinByteStart = startBit % 8; - if (!sig->intelByteOrder) - { - bitWithinByteStart = 7 - bitWithinByteStart; - startBit = (startByte * 8) + bitWithinByteStart; - } - endBit = startBit + sig->signalSize - 1; - if (endBit > 63) - { - endBit = 63; - } - - //bitpattern[startBit / 8] |= 1 << (startBit % 8); + bitpattern[startBit / 8] |= 1 << (startBit % 8); //make the start bit a different color to set it apart ui->bitfield->setReference(bitpattern, false); - for (int y = startBit; y <= endBit; y++) + if (sig->intelByteOrder) { - int byt = y / 8; - bitpattern[byt] |= 1 << (y % 8); - } - ui->bitfield->updateData(bitpattern, true); + endBit = startBit + sig->signalSize - 1; + if (startBit < 0) startBit = 0; + if (endBit > 63) endBit = 63; + for (int y = startBit; y <= endBit; y++) + { + int byt = y / 8; + bitpattern[byt] |= 1 << (y % 8); + } + } + else //big endian / motorola format + { + //much more irritating than the intel version... + int size = sig->signalSize; + while (size > 0) + { + int byt = startBit / 8; + bitpattern[byt] |= 1 << (startBit % 8); + size--; + if ((startBit % 8) == 0) startBit += 15; + else startBit--; + } + } + + ui->bitfield->updateData(bitpattern, true); ui->cbIntelFormat->setChecked(sig->intelByteOrder); switch (sig->valType) @@ -447,7 +455,7 @@ void DBCSignalEditor::clickSignalList(int row) void DBCSignalEditor::bitfieldClicked(int x, int y) { - int bit = (x) + (y * 8); + int bit = (7 - x) + (y * 8); if (currentSignal == NULL) return; currentSignal->startBit = bit; fillSignalForm(currentSignal); diff --git a/flowviewwindow.cpp b/flowviewwindow.cpp index 51e9747..acd6ebf 100644 --- a/flowviewwindow.cpp +++ b/flowviewwindow.cpp @@ -156,9 +156,11 @@ void FlowViewWindow::plottableDoubleClick(QCPAbstractPlottable* plottable, QMous void FlowViewWindow::gotCenterTimeID(int32_t ID, double timestamp) { - if (secondsMode) timestamp *= 1000000.0; //frames always store timestamp in microseconds + uint64_t t_stamp; - qDebug() << "timestamp: " << timestamp; + t_stamp = timestamp * 1000000l; + + qDebug() << "timestamp: " << t_stamp; changeID(QString::number(ID)); //to be sure we're focused on the proper ID @@ -175,7 +177,7 @@ void FlowViewWindow::gotCenterTimeID(int32_t ID, double timestamp) int bestIdx = -1; for (int i = 0; i < frameCache.count(); i++) { - if (frameCache[i].timestamp > timestamp) + if (frameCache[i].timestamp > t_stamp) { bestIdx = i - 1; break; @@ -286,6 +288,7 @@ void FlowViewWindow::saveFileFlow() void FlowViewWindow::updatedFrames(int numFrames) { + CANFrame thisFrame; if (numFrames == -1) //all frames deleted. Kill the display { ui->listFrameID->clear(); @@ -313,6 +316,26 @@ void FlowViewWindow::updatedFrames(int numFrames) } else //just got some new frames. See if they are relevant. { + int refID = frameCache[0].ID; + bool needRefresh = false; + for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++) + { + thisFrame = modelFrames->at(i); + if (thisFrame.ID == refID) + { + frameCache.append(thisFrame); + if (ui->cbLiveMode->checkState() == Qt::Checked) + { + currentPosition = frameCache.count() - 1; + needRefresh = true; + } + } + } + if (needRefresh) + { + updateDataView(); + if (ui->cbSync->checkState() == Qt::Checked) emit sendCenterTimeID(frameCache[currentPosition].ID, frameCache[currentPosition].timestamp / 1000000.0); + } } } @@ -489,7 +512,7 @@ void FlowViewWindow::changeLooping(bool check) void FlowViewWindow::timerTriggered() { - if (!playbackActive) + if (!playbackActive || (ui->cbLiveMode->checkState() == Qt::Checked)) { playbackTimer->stop(); return; diff --git a/flowviewwindow.ui b/flowviewwindow.ui index e06b7ae..2ea56f3 100644 --- a/flowviewwindow.ui +++ b/flowviewwindow.ui @@ -52,7 +52,7 @@ - + @@ -195,6 +195,13 @@ + + + + Live Mode (No Playback) + + +