Better support for loading BLF files. Now files with uncompressed portions and newer container types should also work.
This commit is contained in:
+58
-19
@@ -14,8 +14,10 @@ BLFHandler::BLFHandler()
|
|||||||
/*
|
/*
|
||||||
Written while peeking at source code here:
|
Written while peeking at source code here:
|
||||||
https://python-can.readthedocs.io/en/latest/_modules/can/io/blf.html
|
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<CANFrame>* frames)
|
bool BLFHandler::loadBLF(QString filename, QVector<CANFrame>* frames)
|
||||||
{
|
{
|
||||||
@@ -26,6 +28,7 @@ bool BLFHandler::loadBLF(QString filename, QVector<CANFrame>* frames)
|
|||||||
BLF_OBJECT obj;
|
BLF_OBJECT obj;
|
||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
BLF_CAN_OBJ canObject;
|
BLF_CAN_OBJ canObject;
|
||||||
|
BLF_CAN_OBJ2 canObject2;
|
||||||
|
|
||||||
QFile *inFile = new QFile(filename);
|
QFile *inFile = new QFile(filename);
|
||||||
|
|
||||||
@@ -44,22 +47,35 @@ bool BLFHandler::loadBLF(QString filename, QVector<CANFrame>* frames)
|
|||||||
while (!inFile->atEnd())
|
while (!inFile->atEnd())
|
||||||
{
|
{
|
||||||
qDebug() << "Position within file: " << inFile->pos();
|
qDebug() << "Position within file: " << inFile->pos();
|
||||||
inFile->read((char *)&objHeader, sizeof(objHeader));
|
inFile->read((char *)&objHeader.base, sizeof(BLF_OBJ_HEADER_BASE));
|
||||||
if (qFromLittleEndian(objHeader.sig) == 0x4A424F4C)
|
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;
|
qDebug() << "Proper object header token. Read Size: " << readSize;
|
||||||
fileData = inFile->read(readSize);
|
fileData = inFile->read(readSize);
|
||||||
junk = inFile->read(readSize % 4); //file is padded so sizes must always end up on even multiple of 4
|
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);
|
//qDebug() << "Fudge bytes in readSize: " << (readSize % 4);
|
||||||
if (objHeader.objType == BLF_CONTAINER)
|
|
||||||
|
switch (objHeader.base.objType)
|
||||||
{
|
{
|
||||||
qDebug() << "Object is a container. Uncompressing it";
|
case BLF_CONTAINER:
|
||||||
fileData.prepend(objHeader.uncompSize & 0xFF);
|
qDebug() << "Object is a container.";
|
||||||
fileData.prepend((objHeader.uncompSize >> 8) & 0xFF);
|
memcpy(&objHeader.containerObj, fileData.constData(), sizeof(BLF_OBJ_HEADER_CONTAINER));
|
||||||
fileData.prepend((objHeader.uncompSize >> 16) & 0xFF);
|
fileData.remove(0, sizeof(BLF_OBJ_HEADER_CONTAINER));
|
||||||
fileData.prepend((objHeader.uncompSize >> 24) & 0xFF);
|
if (objHeader.containerObj.compressionMethod == BLF_CONT_NO_COMPRESSION)
|
||||||
uncompressedData += qUncompress(fileData);
|
{
|
||||||
|
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();
|
qDebug() << "Uncompressed size: " << uncompressedData.count();
|
||||||
pos = 0;
|
pos = 0;
|
||||||
bool foundHeader = false;
|
bool foundHeader = false;
|
||||||
@@ -73,12 +89,13 @@ bool BLFHandler::loadBLF(QString filename, QVector<CANFrame>* frames)
|
|||||||
//then process all the objects
|
//then process all the objects
|
||||||
while ( (int)(pos + sizeof(BLF_OBJ_HEADER)) < uncompressedData.count())
|
while ( (int)(pos + sizeof(BLF_OBJ_HEADER)) < uncompressedData.count())
|
||||||
{
|
{
|
||||||
memcpy(&obj.header, (uncompressedData.constData() + pos), sizeof(BLF_OBJ_HEADER));
|
memcpy(&obj.header.base, (uncompressedData.constData() + pos), sizeof(BLF_OBJ_HEADER_BASE));
|
||||||
qDebug() << "Pos: " << pos << " Type: " << obj.header.objType << "Obj Size: " << obj.header.objSize;
|
memcpy(&obj.header.v1Obj, (uncompressedData.constData() + pos) + sizeof(BLF_OBJ_HEADER_BASE), sizeof(BLF_OBJ_HEADER_V1));
|
||||||
if (qFromLittleEndian(objHeader.sig) == 0x4A424F4C)
|
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));
|
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.objType == BLF_CAN_MSG)
|
if (obj.header.base.objType == BLF_CAN_MSG)
|
||||||
{
|
{
|
||||||
memcpy(&canObject, fileData.constData(), sizeof(BLF_CAN_OBJ));
|
memcpy(&canObject, fileData.constData(), sizeof(BLF_CAN_OBJ));
|
||||||
CANFrame frame;
|
CANFrame frame;
|
||||||
@@ -95,16 +112,36 @@ bool BLFHandler::loadBLF(QString filename, QVector<CANFrame>* frames)
|
|||||||
for (int i = 0; i < 8; i++) frame.data[i] = canObject.data[i];
|
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?
|
//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);
|
frames->append(frame);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//qDebug() << "Not a can frame! ObjType: " << obj.header.objType;
|
//qDebug() << "Not a can frame! ObjType: " << obj.header.objType;
|
||||||
if (obj.header.objType > 0xFFFF)
|
if (obj.header.base.objType > 0xFFFF)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pos += obj.header.objSize + (obj.header.objSize % 4);
|
pos += obj.header.base.objSize + (obj.header.base.objSize % 4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -114,6 +151,8 @@ bool BLFHandler::loadBLF(QString filename, QVector<CANFrame>* frames)
|
|||||||
}
|
}
|
||||||
uncompressedData.remove(0, pos);
|
uncompressedData.remove(0, pos);
|
||||||
qDebug() << "After removing used data uncompressedData is now this big: " << uncompressedData.count();
|
qDebug() << "After removing used data uncompressedData is now this big: " << uncompressedData.count();
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
|
|||||||
+114
-3
@@ -10,8 +10,31 @@ enum
|
|||||||
{
|
{
|
||||||
BLF_CAN_MSG = 1,
|
BLF_CAN_MSG = 1,
|
||||||
BLF_CAN_ERR = 2,
|
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_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_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
|
struct BLF_FILE_HEADER
|
||||||
@@ -35,18 +58,51 @@ struct BLF_FILE_HEADER
|
|||||||
uint8_t unused[72];
|
uint8_t unused[72];
|
||||||
}; //144 bytes
|
}; //144 bytes
|
||||||
|
|
||||||
struct BLF_OBJ_HEADER
|
struct BLF_OBJ_HEADER_BASE
|
||||||
{
|
{
|
||||||
uint32_t sig; //0 offset from start
|
uint32_t sig; //0 offset from start
|
||||||
uint16_t headerSize; //4
|
uint16_t headerSize; //4
|
||||||
uint16_t headerVersion; //6
|
uint16_t headerVersion; //6
|
||||||
uint32_t objSize; //8
|
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
|
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
|
uint16_t objVer; //22
|
||||||
uint64_t uncompSize; //24
|
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
|
struct BLF_OBJECT
|
||||||
{
|
{
|
||||||
@@ -63,6 +119,61 @@ struct BLF_CAN_OBJ
|
|||||||
uint8_t data[8];
|
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
|
class BLFHandler
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user