Add support for loading BLF files. Only loads CAN frames at this point.
This commit is contained in:
+4
-2
@@ -64,7 +64,8 @@ SOURCES += main.cpp\
|
|||||||
bus_protocols/uds_handler.cpp \
|
bus_protocols/uds_handler.cpp \
|
||||||
jsedit.cpp \
|
jsedit.cpp \
|
||||||
frameplaybackobject.cpp \
|
frameplaybackobject.cpp \
|
||||||
helpwindow.cpp
|
helpwindow.cpp \
|
||||||
|
blfhandler.cpp
|
||||||
|
|
||||||
HEADERS += mainwindow.h \
|
HEADERS += mainwindow.h \
|
||||||
can_structs.h \
|
can_structs.h \
|
||||||
@@ -119,7 +120,8 @@ HEADERS += mainwindow.h \
|
|||||||
bus_protocols/isotp_message.h \
|
bus_protocols/isotp_message.h \
|
||||||
jsedit.h \
|
jsedit.h \
|
||||||
frameplaybackobject.h \
|
frameplaybackobject.h \
|
||||||
helpwindow.h
|
helpwindow.h \
|
||||||
|
blfhandler.h
|
||||||
|
|
||||||
FORMS += ui/candatagrid.ui \
|
FORMS += ui/candatagrid.ui \
|
||||||
ui/connectionwindow.ui \
|
ui/connectionwindow.ui \
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#include "blfhandler.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QString>
|
||||||
|
#include <QtEndian>
|
||||||
|
|
||||||
|
BLFHandler::BLFHandler()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Written while peeking at source code here:
|
||||||
|
https://python-can.readthedocs.io/en/latest/_modules/can/io/blf.html
|
||||||
|
|
||||||
|
All the code actually below is freshly written though.
|
||||||
|
*/
|
||||||
|
bool BLFHandler::loadBLF(QString filename, QVector<CANFrame>* frames)
|
||||||
|
{
|
||||||
|
BLF_OBJ_HEADER objHeader;
|
||||||
|
QByteArray fileData;
|
||||||
|
QByteArray uncompressedData;
|
||||||
|
QByteArray junk;
|
||||||
|
BLF_OBJECT obj;
|
||||||
|
uint32_t pos;
|
||||||
|
BLF_CAN_OBJ canObject;
|
||||||
|
|
||||||
|
QFile *inFile = new QFile(filename);
|
||||||
|
|
||||||
|
if (!inFile->open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
delete inFile;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
inFile->read((char *)&header, sizeof(header));
|
||||||
|
if (qFromLittleEndian(header.sig) == 0x47474F4C)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
|
||||||
|
while (!inFile->atEnd())
|
||||||
|
{
|
||||||
|
inFile->read((char *)&objHeader, sizeof(objHeader));
|
||||||
|
if (qFromLittleEndian(objHeader.sig) == 0x4A424F4C)
|
||||||
|
{
|
||||||
|
int readSize = objHeader.objSize - sizeof(BLF_OBJ_HEADER);
|
||||||
|
fileData = inFile->read(readSize);
|
||||||
|
junk = inFile->read(readSize % 4); //file is padded so sizes must always end up on even multiple of 4
|
||||||
|
if (objHeader.objType == BLF_CONTAINER)
|
||||||
|
{
|
||||||
|
fileData.prepend(objHeader.uncompSize & 0xFF);
|
||||||
|
fileData.prepend((objHeader.uncompSize >> 8) & 0xFF);
|
||||||
|
fileData.prepend((objHeader.uncompSize >> 16) & 0xFF);
|
||||||
|
fileData.prepend((objHeader.uncompSize >> 24) & 0xFF);
|
||||||
|
uncompressedData += qUncompress(fileData);
|
||||||
|
pos = 0;
|
||||||
|
while (pos + sizeof(BLF_OBJ_HEADER) < uncompressedData.count())
|
||||||
|
{
|
||||||
|
memcpy(&obj.header, uncompressedData.mid(pos, sizeof(BLF_OBJ_HEADER)).constData(), sizeof(BLF_OBJ_HEADER));
|
||||||
|
if (qFromLittleEndian(objHeader.sig) == 0x4A424F4C)
|
||||||
|
{
|
||||||
|
fileData = uncompressedData.mid(pos + sizeof(BLF_OBJ_HEADER), obj.header.objSize - sizeof(BLF_OBJ_HEADER));
|
||||||
|
if (obj.header.objType == BLF_CAN_MSG)
|
||||||
|
{
|
||||||
|
memcpy(&canObject, fileData.constData(), sizeof(BLF_CAN_OBJ));
|
||||||
|
CANFrame frame;
|
||||||
|
frame.bus = canObject.channel;
|
||||||
|
frame.extended = (canObject.id & 0x80000000ull)?true:false;
|
||||||
|
frame.ID = canObject.id & 0x1FFFFFFFull;
|
||||||
|
frame.isReceived = true;
|
||||||
|
frame.len = canObject.dlc;
|
||||||
|
frame.timestamp = obj.header.uncompSize / 1000000.0; //uncompsize field also used for timestamp oddly enough
|
||||||
|
for (int i = 0; i < 8; i++) frame.data[i] = canObject.data[i];
|
||||||
|
frames->append(frame);
|
||||||
|
}
|
||||||
|
pos += obj.header.objSize + (obj.header.objSize % 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uncompressedData.remove(0, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#ifndef BLFHANDLER_H
|
||||||
|
#define BLFHANDLER_H
|
||||||
|
|
||||||
|
#include <Qt>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QList>
|
||||||
|
#include "can_structs.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
BLF_CAN_MSG = 1,
|
||||||
|
BLF_CAN_ERR = 2,
|
||||||
|
BLF_CONTAINER = 10,
|
||||||
|
BLF_GLOBAL_MARKER = 96,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BLF_FILE_HEADER
|
||||||
|
{
|
||||||
|
uint32_t sig;
|
||||||
|
uint32_t headerSize;
|
||||||
|
uint8_t appID;
|
||||||
|
uint8_t appVerMajor;
|
||||||
|
uint8_t appVerMinor;
|
||||||
|
uint8_t appVerBuild;
|
||||||
|
uint8_t binLogVerMajor;
|
||||||
|
uint8_t binLogVerMinor;
|
||||||
|
uint8_t binLogVerBuild;
|
||||||
|
uint8_t binLogVerPatch;
|
||||||
|
uint64_t fileSize;
|
||||||
|
uint64_t uncompressedFileSize;
|
||||||
|
uint32_t countObjs;
|
||||||
|
uint32_t countObjsRead;
|
||||||
|
uint8_t startTime[16];
|
||||||
|
uint8_t stopTime[16];
|
||||||
|
uint8_t unused[72];
|
||||||
|
}; //144 bytes
|
||||||
|
|
||||||
|
struct BLF_OBJ_HEADER
|
||||||
|
{
|
||||||
|
uint32_t sig;
|
||||||
|
uint16_t headerSize;
|
||||||
|
uint16_t headerVersion;
|
||||||
|
uint32_t objSize;
|
||||||
|
uint32_t objType;
|
||||||
|
uint32_t flags;
|
||||||
|
uint16_t nothing;
|
||||||
|
uint16_t objVer;
|
||||||
|
uint64_t uncompSize;
|
||||||
|
}; //32 bytes
|
||||||
|
|
||||||
|
struct BLF_OBJECT
|
||||||
|
{
|
||||||
|
BLF_OBJ_HEADER header;
|
||||||
|
QByteArray data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BLF_CAN_OBJ
|
||||||
|
{
|
||||||
|
uint16_t channel;
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t dlc;
|
||||||
|
uint32_t id;
|
||||||
|
uint8_t data[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BLFHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BLFHandler();
|
||||||
|
bool loadBLF(QString filename, QVector<CANFrame>* frames);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BLF_FILE_HEADER header;
|
||||||
|
QList<BLF_OBJECT> objects;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BLFHANDLER_H
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
#include "blfhandler.h"
|
||||||
|
|
||||||
QFile FrameFileIO::continuousFile;
|
QFile FrameFileIO::continuousFile;
|
||||||
|
|
||||||
@@ -138,6 +139,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
|
|||||||
filters.append(QString(tr("Kvaser Log Decimal (*.txt *.TXT)")));
|
filters.append(QString(tr("Kvaser Log Decimal (*.txt *.TXT)")));
|
||||||
filters.append(QString(tr("Kvaser Log Hex (*.txt *.TXT)")));
|
filters.append(QString(tr("Kvaser Log Hex (*.txt *.TXT)")));
|
||||||
filters.append(QString(tr("CANalyzer Ascii Log (*.asc *.ASC)")));
|
filters.append(QString(tr("CANalyzer Ascii Log (*.asc *.ASC)")));
|
||||||
|
filters.append(QString(tr("CANalyzer Binary Log Files (*.blf *.BLF)")));
|
||||||
|
|
||||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
dialog.setNameFilters(filters);
|
dialog.setNameFilters(filters);
|
||||||
@@ -171,6 +173,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
|
|||||||
if (dialog.selectedNameFilter() == filters[11]) result = loadKvaserFile(filename, frameCache, false);
|
if (dialog.selectedNameFilter() == filters[11]) result = loadKvaserFile(filename, frameCache, false);
|
||||||
if (dialog.selectedNameFilter() == filters[12]) result = loadKvaserFile(filename, frameCache, true);
|
if (dialog.selectedNameFilter() == filters[12]) result = loadKvaserFile(filename, frameCache, true);
|
||||||
if (dialog.selectedNameFilter() == filters[13]) result = loadCanalyzerASC(filename, frameCache);
|
if (dialog.selectedNameFilter() == filters[13]) result = loadCanalyzerASC(filename, frameCache);
|
||||||
|
if (dialog.selectedNameFilter() == filters[14]) result = loadCanalyzerBLF(filename, frameCache);
|
||||||
|
|
||||||
progress.cancel();
|
progress.cancel();
|
||||||
|
|
||||||
@@ -588,6 +591,12 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector<CANFrame>* frames)
|
|||||||
return !foundErrors;
|
return !foundErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FrameFileIO::loadCanalyzerBLF(QString filename, QVector<CANFrame> *frames)
|
||||||
|
{
|
||||||
|
BLFHandler blf;
|
||||||
|
blf.loadBLF(filename, frames);
|
||||||
|
}
|
||||||
|
|
||||||
//The "native" file format for this program
|
//The "native" file format for this program
|
||||||
bool FrameFileIO::loadNativeCSVFile(QString filename, QVector<CANFrame>* frames)
|
bool FrameFileIO::loadNativeCSVFile(QString filename, QVector<CANFrame>* frames)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public:
|
|||||||
static bool loadPCANFile(QString, QVector<CANFrame>*);
|
static bool loadPCANFile(QString, QVector<CANFrame>*);
|
||||||
static bool loadKvaserFile(QString, QVector<CANFrame>*, bool);
|
static bool loadKvaserFile(QString, QVector<CANFrame>*, bool);
|
||||||
static bool loadCanalyzerASC(QString, QVector<CANFrame>*);
|
static bool loadCanalyzerASC(QString, QVector<CANFrame>*);
|
||||||
|
static bool loadCanalyzerBLF(QString, QVector<CANFrame>*);
|
||||||
static bool saveCRTDFile(QString, const QVector<CANFrame>*);
|
static bool saveCRTDFile(QString, const QVector<CANFrame>*);
|
||||||
static bool saveNativeCSVFile(QString, const QVector<CANFrame>*);
|
static bool saveNativeCSVFile(QString, const QVector<CANFrame>*);
|
||||||
static bool saveGenericCSVFile(QString, const QVector<CANFrame>*);
|
static bool saveGenericCSVFile(QString, const QVector<CANFrame>*);
|
||||||
|
|||||||
Reference in New Issue
Block a user