From c60eac7364cd6a561db422bfb8c91b47007e59a8 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 8 Feb 2018 20:47:13 -0500 Subject: [PATCH] Add support for loading BLF files. Only loads CAN frames at this point. --- SavvyCAN.pro | 6 ++-- blfhandler.cpp | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ blfhandler.h | 78 ++++++++++++++++++++++++++++++++++++++++++++ framefileio.cpp | 9 ++++++ framefileio.h | 1 + 5 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 blfhandler.cpp create mode 100644 blfhandler.h diff --git a/SavvyCAN.pro b/SavvyCAN.pro index b9507cf..84b6308 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -64,7 +64,8 @@ SOURCES += main.cpp\ bus_protocols/uds_handler.cpp \ jsedit.cpp \ frameplaybackobject.cpp \ - helpwindow.cpp + helpwindow.cpp \ + blfhandler.cpp HEADERS += mainwindow.h \ can_structs.h \ @@ -119,7 +120,8 @@ HEADERS += mainwindow.h \ bus_protocols/isotp_message.h \ jsedit.h \ frameplaybackobject.h \ - helpwindow.h + helpwindow.h \ + blfhandler.h FORMS += ui/candatagrid.ui \ ui/connectionwindow.ui \ diff --git a/blfhandler.cpp b/blfhandler.cpp new file mode 100644 index 0000000..a86a0d5 --- /dev/null +++ b/blfhandler.cpp @@ -0,0 +1,86 @@ +#include "blfhandler.h" +#include +#include +#include +#include + +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* 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; +} diff --git a/blfhandler.h b/blfhandler.h new file mode 100644 index 0000000..15394c6 --- /dev/null +++ b/blfhandler.h @@ -0,0 +1,78 @@ +#ifndef BLFHANDLER_H +#define BLFHANDLER_H + +#include +#include +#include +#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* frames); + +private: + BLF_FILE_HEADER header; + QList objects; +}; + +#endif // BLFHANDLER_H diff --git a/framefileio.cpp b/framefileio.cpp index f0f17bc..c4b9d35 100644 --- a/framefileio.cpp +++ b/framefileio.cpp @@ -6,6 +6,7 @@ #include #include "utility.h" +#include "blfhandler.h" QFile FrameFileIO::continuousFile; @@ -138,6 +139,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector* frameCache filters.append(QString(tr("Kvaser Log Decimal (*.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 Binary Log Files (*.blf *.BLF)"))); dialog.setFileMode(QFileDialog::ExistingFile); dialog.setNameFilters(filters); @@ -171,6 +173,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector* frameCache if (dialog.selectedNameFilter() == filters[11]) result = loadKvaserFile(filename, frameCache, false); if (dialog.selectedNameFilter() == filters[12]) result = loadKvaserFile(filename, frameCache, true); if (dialog.selectedNameFilter() == filters[13]) result = loadCanalyzerASC(filename, frameCache); + if (dialog.selectedNameFilter() == filters[14]) result = loadCanalyzerBLF(filename, frameCache); progress.cancel(); @@ -588,6 +591,12 @@ bool FrameFileIO::loadCanalyzerASC(QString filename, QVector* frames) return !foundErrors; } +bool FrameFileIO::loadCanalyzerBLF(QString filename, QVector *frames) +{ + BLFHandler blf; + blf.loadBLF(filename, frames); +} + //The "native" file format for this program bool FrameFileIO::loadNativeCSVFile(QString filename, QVector* frames) { diff --git a/framefileio.h b/framefileio.h index 2081bfd..5015782 100644 --- a/framefileio.h +++ b/framefileio.h @@ -43,6 +43,7 @@ public: static bool loadPCANFile(QString, QVector*); static bool loadKvaserFile(QString, QVector*, bool); static bool loadCanalyzerASC(QString, QVector*); + static bool loadCanalyzerBLF(QString, QVector*); static bool saveCRTDFile(QString, const QVector*); static bool saveNativeCSVFile(QString, const QVector*); static bool saveGenericCSVFile(QString, const QVector*);