From 229121c3a4ba2e71cfb7fe6aa1a17f3de9c40b85 Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Thu, 1 Aug 2019 19:33:33 -0400 Subject: [PATCH] Better support for loading BLF files. Now files with uncompressed portions and newer container types should also work. --- blfhandler.cpp | 77 ++++++++++++++++++++++++-------- blfhandler.h | 119 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 173 insertions(+), 23 deletions(-) diff --git a/blfhandler.cpp b/blfhandler.cpp index 49e9694..7dde7b3 100644 --- a/blfhandler.cpp +++ b/blfhandler.cpp @@ -14,8 +14,10 @@ BLFHandler::BLFHandler() /* Written while peeking at source code here: https://python-can.readthedocs.io/en/latest/_modules/can/io/blf.html +https://bitbucket.org/tobylorenz/vector_blf/ -All the code actually below is freshly written though. +All the code actually below is freshly written but heavily based upon things seen in those +two source repos. */ bool BLFHandler::loadBLF(QString filename, QVector* frames) { @@ -26,6 +28,7 @@ bool BLFHandler::loadBLF(QString filename, QVector* frames) BLF_OBJECT obj; uint32_t pos; BLF_CAN_OBJ canObject; + BLF_CAN_OBJ2 canObject2; QFile *inFile = new QFile(filename); @@ -44,22 +47,35 @@ bool BLFHandler::loadBLF(QString filename, QVector* frames) while (!inFile->atEnd()) { qDebug() << "Position within file: " << inFile->pos(); - inFile->read((char *)&objHeader, sizeof(objHeader)); - if (qFromLittleEndian(objHeader.sig) == 0x4A424F4C) + inFile->read((char *)&objHeader.base, sizeof(BLF_OBJ_HEADER_BASE)); + if (qFromLittleEndian(objHeader.base.sig) == 0x4A424F4C) { - int readSize = objHeader.objSize - sizeof(BLF_OBJ_HEADER); + int readSize = objHeader.base.objSize - sizeof(BLF_OBJ_HEADER_BASE); qDebug() << "Proper object header token. Read Size: " << readSize; fileData = inFile->read(readSize); junk = inFile->read(readSize % 4); //file is padded so sizes must always end up on even multiple of 4 //qDebug() << "Fudge bytes in readSize: " << (readSize % 4); - if (objHeader.objType == BLF_CONTAINER) + + switch (objHeader.base.objType) { - qDebug() << "Object is a container. Uncompressing it"; - 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); + case BLF_CONTAINER: + qDebug() << "Object is a container."; + memcpy(&objHeader.containerObj, fileData.constData(), sizeof(BLF_OBJ_HEADER_CONTAINER)); + fileData.remove(0, sizeof(BLF_OBJ_HEADER_CONTAINER)); + if (objHeader.containerObj.compressionMethod == BLF_CONT_NO_COMPRESSION) + { + qDebug() << "Container is not compressed"; + uncompressedData = fileData; + } + if (objHeader.containerObj.compressionMethod == BLF_CONT_ZLIB_COMPRESSION) + { + qDebug() << "Compressed container. Unpacking it."; + fileData.prepend(objHeader.containerObj.uncompressedSize & 0xFF); + fileData.prepend((objHeader.containerObj.uncompressedSize >> 8) & 0xFF); + fileData.prepend((objHeader.containerObj.uncompressedSize >> 16) & 0xFF); + fileData.prepend((objHeader.containerObj.uncompressedSize >> 24) & 0xFF); + uncompressedData += qUncompress(fileData); + } qDebug() << "Uncompressed size: " << uncompressedData.count(); pos = 0; bool foundHeader = false; @@ -73,12 +89,13 @@ bool BLFHandler::loadBLF(QString filename, QVector* frames) //then process all the objects while ( (int)(pos + sizeof(BLF_OBJ_HEADER)) < uncompressedData.count()) { - memcpy(&obj.header, (uncompressedData.constData() + pos), sizeof(BLF_OBJ_HEADER)); - qDebug() << "Pos: " << pos << " Type: " << obj.header.objType << "Obj Size: " << obj.header.objSize; - if (qFromLittleEndian(objHeader.sig) == 0x4A424F4C) + memcpy(&obj.header.base, (uncompressedData.constData() + pos), sizeof(BLF_OBJ_HEADER_BASE)); + memcpy(&obj.header.v1Obj, (uncompressedData.constData() + pos) + sizeof(BLF_OBJ_HEADER_BASE), sizeof(BLF_OBJ_HEADER_V1)); + qDebug() << "Pos: " << pos << " Type: " << obj.header.base.objType << "Obj Size: " << obj.header.base.objSize; + if (qFromLittleEndian(objHeader.base.sig) == 0x4A424F4C) { - fileData = uncompressedData.mid(pos + sizeof(BLF_OBJ_HEADER), obj.header.objSize - sizeof(BLF_OBJ_HEADER)); - if (obj.header.objType == BLF_CAN_MSG) + fileData = uncompressedData.mid(pos + sizeof(BLF_OBJ_HEADER_BASE) + sizeof(BLF_OBJ_HEADER_V1), obj.header.base.objSize - sizeof(BLF_OBJ_HEADER_BASE) - sizeof(BLF_OBJ_HEADER_V1)); + if (obj.header.base.objType == BLF_CAN_MSG) { memcpy(&canObject, fileData.constData(), sizeof(BLF_CAN_OBJ)); CANFrame frame; @@ -95,16 +112,36 @@ bool BLFHandler::loadBLF(QString filename, QVector* frames) for (int i = 0; i < 8; i++) frame.data[i] = canObject.data[i]; } //Should we divide by a thousand or a million? Unsure here. It appears some logs are stamped in microseconds and some in milliseconds? - frame.timestamp = obj.header.uncompSize / 1000.0; //uncompsize field also used for timestamp oddly enough + frame.timestamp = obj.header.v1Obj.uncompSize / 1000.0; //uncompsize field also used for timestamp oddly enough + frames->append(frame); + } + else if (obj.header.base.objType == BLF_CAN_MSG2) + { + memcpy(&canObject2, fileData.constData(), sizeof(BLF_CAN_OBJ2)); + CANFrame frame; + frame.bus = canObject2.channel; + frame.extended = (canObject2.id & 0x80000000ull)?true:false; + frame.ID = canObject2.id & 0x1FFFFFFFull; + frame.isReceived = true; + frame.len = canObject2.dlc; + + if (canObject2.flags & BLF_REMOTE_FLAG) { + frame.remote = true; + } else { + frame.remote = false; + for (int i = 0; i < 8; i++) frame.data[i] = canObject2.data[i]; + } + //Should we divide by a thousand or a million? Unsure here. It appears some logs are stamped in microseconds and some in milliseconds? + frame.timestamp = obj.header.v1Obj.uncompSize / 1000.0; //uncompsize field also used for timestamp oddly enough frames->append(frame); } else { //qDebug() << "Not a can frame! ObjType: " << obj.header.objType; - if (obj.header.objType > 0xFFFF) + if (obj.header.base.objType > 0xFFFF) return false; } - pos += obj.header.objSize + (obj.header.objSize % 4); + pos += obj.header.base.objSize + (obj.header.base.objSize % 4); } else { @@ -114,6 +151,8 @@ bool BLFHandler::loadBLF(QString filename, QVector* frames) } uncompressedData.remove(0, pos); qDebug() << "After removing used data uncompressedData is now this big: " << uncompressedData.count(); + + break; } } else return false; diff --git a/blfhandler.h b/blfhandler.h index fb158c0..18b5548 100644 --- a/blfhandler.h +++ b/blfhandler.h @@ -10,8 +10,31 @@ enum { BLF_CAN_MSG = 1, BLF_CAN_ERR = 2, + BLF_CAN_OVERLOAD = 3, + BLF_STATISTIC = 4, + BLF_APP_TRIGGER = 5, + BLF_ENV_INT = 6, + BLF_ENV_DOUBLE = 7, + BLF_ENV_STRING = 8, + BLF_ENV_DATA = 9, BLF_CONTAINER = 10, + BLF_CAN_DRV_ERR = 31, // can driver error + BLF_CAN_DRV_SYNC = 44, + BLF_ERROR_EXT = 73, + BLF_DRV_ERR_EXT = 74, + BLF_CAN_MSG2 = 86, + BLF_OVERRUN = 91, + BLF_EVENT_COMMENT = 92, BLF_GLOBAL_MARKER = 96, + BLF_CAN_FD_MSG = 100, + BLF_CAN_FD_MSG64 = 101, + BLF_CAN_FD_ERR64 = 104 +}; + +enum +{ + BLF_CONT_NO_COMPRESSION = 0, + BLF_CONT_ZLIB_COMPRESSION = 2 }; struct BLF_FILE_HEADER @@ -35,18 +58,51 @@ struct BLF_FILE_HEADER uint8_t unused[72]; }; //144 bytes -struct BLF_OBJ_HEADER +struct BLF_OBJ_HEADER_BASE { uint32_t sig; //0 offset from start uint16_t headerSize; //4 uint16_t headerVersion; //6 uint32_t objSize; //8 - uint32_t objType; //12 + uint32_t objType; //12 +}; //16 bytes in common + +//the next three are continuations of the above base and so are numbered in comments accordingly +struct BLF_OBJ_HEADER_V1 +{ uint32_t flags; //16 - uint16_t nothing; //20 + uint16_t clientIdx; //20 + uint16_t objVer; //22 + uint64_t uncompSize; //24 could be the timestamp too +}; //ends up as 32 bytes for this whole header including base + +struct BLF_OBJ_HEADER_V2 +{ + uint32_t flags; //16 + uint16_t timestampStatus; //20 uint16_t objVer; //22 uint64_t uncompSize; //24 -}; //32 bytes + uint64_t origTimestamp; //32 +}; //40 bytes including base header + +struct BLF_OBJ_HEADER_CONTAINER +{ + uint16_t compressionMethod; //16 + uint8_t notused[6]; //18 + uint32_t uncompressedSize; //24 + uint8_t notused2[4]; //28 +}; //32 bytes for the whole header + +struct BLF_OBJ_HEADER +{ + BLF_OBJ_HEADER_BASE base; + union + { + BLF_OBJ_HEADER_V1 v1Obj; + BLF_OBJ_HEADER_V2 V2Obj; + BLF_OBJ_HEADER_CONTAINER containerObj; + }; +}; struct BLF_OBJECT { @@ -63,6 +119,61 @@ struct BLF_CAN_OBJ uint8_t data[8]; }; +struct BLF_CAN_OBJ2 +{ + uint16_t channel; + uint8_t flags; //0 = Tx, 5 = Err 6 = WU, 7 = RTR + uint8_t dlc; + uint32_t id; + uint8_t data[8]; + uint32_t frameLength; //length of transmission in nanoseconds not covering IF or EOF + uint8_t bitCount; //# of bits in this message including IF and EOF + uint8_t dummy1; + uint16_t dummy2; +}; + +struct BLF_CANFD_OBJ +{ + uint16_t channel; + uint8_t flags; + uint8_t dlc; + uint32_t id; + uint32_t frameLen; + uint8_t bitCount; + uint8_t fdFlags; + uint8_t validDataBytes; + uint8_t nonUseful[5]; + uint8_t data[64]; +}; + +struct BLF_ERROR_EXT +{ + uint16_t channel; + uint16_t len; + uint32_t flags; + uint8_t ecc; + uint8_t position; + uint8_t dlc; + uint8_t ignored; + uint32_t frameLen; + uint32_t id; + uint16_t extFlags; + uint16_t ignore2; + uint8_t data; +}; + +struct BLF_GLOBAL_MARKER +{ + uint32_t eventType; + uint32_t foregroundColor; + uint32_t backgroundColor; + uint8_t ignore[3]; + uint8_t relocatable; + uint32_t groupNameLen; + uint32_t markerNameLen; + uint32_t descLen; + uint8_t ignore2[12]; +}; class BLFHandler {