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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
#include "blfhandler.h"
#include <QDebug>
#include <QFile>
#include <QString>
#include <QtEndian>
#define BLF_REMOTE_FLAG 0x80
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 but heavily based upon things seen in those
two source repos.
*/
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;
BLF_CAN_OBJ2 canObject2;
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)
{
qDebug() << "Proper BLF file header token";
}
else return false;
while (!inFile->atEnd())
{
qDebug() << "Position within file: " << inFile->pos();
inFile->read((char *)&objHeader.base, sizeof(BLF_OBJ_HEADER_BASE));
if (qFromLittleEndian(objHeader.base.sig) == 0x4A424F4C)
{
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);
switch (objHeader.base.objType)
{
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;
}
else 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);
}
else
{
qDebug() << "Dunno what this is... " << objHeader.containerObj.compressionMethod;
}
qDebug() << "Uncompressed size: " << uncompressedData.length();
qDebug() << "Currently loaded frames at this point: " << frames->count();
pos = 0;
//bool foundHeader = false;
//first skip forward to find a header signature - usually not necessary
while ( (int)(pos + sizeof(BLF_OBJ_HEADER)) < uncompressedData.length())
{
int32_t *headerSig = (int32_t *)(uncompressedData.constData() + pos);
if (*headerSig == 0x4A424F4C) break;
pos += 4;
}
//then process all the objects
while ( (int)(pos + sizeof(BLF_OBJ_HEADER)) < uncompressedData.length())
{
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));
//if (obj.header.base.objType != 1)
//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_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;
frame.bus = canObject.channel;
frame.setExtendedFrameFormat((canObject.id & 0x80000000ull)?true:false);
frame.setFrameId(canObject.id & 0x1FFFFFFFull);
frame.isReceived = true;
QByteArray bytes(canObject.dlc, 0);
if (canObject.flags & BLF_REMOTE_FLAG) {
frame.setFrameType(QCanBusFrame::RemoteRequestFrame);
} else {
frame.setFrameType(QCanBusFrame::DataFrame);
for (int i = 0; i < canObject.dlc; i++) bytes[i] = canObject.data[i];
}
frame.setPayload(bytes);
//Should we divide by a thousand or a million? Unsure here. It appears some logs are stamped in microseconds and some in milliseconds?
frame.setTimeStamp(QCanBusFrame::TimeStamp(0, 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.setExtendedFrameFormat((canObject2.id & 0x80000000ull)?true:false);
frame.setFrameId(canObject2.id & 0x1FFFFFFFull);
frame.isReceived = true;
QByteArray bytes(canObject2.dlc, 0);
if (canObject2.flags & BLF_REMOTE_FLAG) {
frame.setFrameType(QCanBusFrame::RemoteRequestFrame);
} else {
frame.setFrameType(QCanBusFrame::DataFrame);
for (int i = 0; i < canObject2.dlc; i++) bytes[i] = canObject2.data[i];
}
frame.setPayload(bytes);
//Should we divide by a thousand or a million? Unsure here. It appears some logs are stamped in microseconds and some in milliseconds?
frame.setTimeStamp(QCanBusFrame::TimeStamp(0, 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.base.objType;
if (obj.header.base.objType > 0xFFFF)
return false;
}
pos += obj.header.base.objSize + (obj.header.base.objSize % 4);
}
else
{
qDebug() << "Unexpected object header signature, aborting";
return false;
}
}
uncompressedData.remove(0, pos);
qDebug() << "After removing used data uncompressedData is now this big: " << uncompressedData.length();
break;
}
}
else return false;
}
return true;
}
bool BLFHandler::saveBLF(QString filename, QVector<CANFrame> *frames)
{
Q_UNUSED(filename)
Q_UNUSED(frames)
return false;
}
|