Merge branch 'master' of github.com:collin80/SavvyCAN

This commit is contained in:
Collin Kidder
2022-05-05 20:05:30 -04:00
6 changed files with 350 additions and 2 deletions
+2
View File
@@ -155,6 +155,8 @@ jobs:
)
release_msg="${release_msg//$'\n'/'-'}"
release_msg="${release_msg//$'\r'/'-'}"
release_msg="${release_msg//$'('/'-'}"
release_msg="${release_msg//$')'/'-'}"
echo $release_msg
echo "::set-output name=msg::$release_msg"
+4 -2
View File
@@ -92,7 +92,8 @@ SOURCES += main.cpp\
re/sniffer/SnifferDelegate.cpp \
connections/newconnectiondialog.cpp \
re/temporalgraphwindow.cpp \
filterutility.cpp
filterutility.cpp \
pcaplite.cpp
HEADERS += mainwindow.h \
can_structs.h \
@@ -178,7 +179,8 @@ HEADERS += mainwindow.h \
re/sniffer/SnifferDelegate.h \
connections/newconnectiondialog.h \
re/temporalgraphwindow.h \
filterutility.h
filterutility.h \
pcaplite.h
FORMS += ui/candatagrid.ui \
ui/dbccomparatorwindow.ui \
+96
View File
@@ -8,6 +8,7 @@
#include <QSettings>
#include <iostream>
#include <memory>
#include "pcaplite.h"
#include "utility.h"
#include "blfhandler.h"
@@ -189,6 +190,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
filters.append(QString(tr("Tesla Autopilot Snapshot (*.CAN *.can)")));
filters.append(QString(tr("CLX000 (*.txt *.TXT)")));
filters.append(QString(tr("CANServer Binary Log (*.log *.LOG)")));
filters.append(QString(tr("Wireshark (*.pcap *.PCAP *.pcapng *.PCAPNG)")));
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::ExistingFile);
@@ -234,6 +236,7 @@ bool FrameFileIO::loadFrameFile(QString &fileName, QVector<CANFrame>* frameCache
if (selectedNameFilter == filters[21]) result = loadTeslaAPFile(filename, frameCache);
if (selectedNameFilter == filters[22]) result = loadCLX000File(filename, frameCache);
if (selectedNameFilter == filters[23]) result = loadCANServerFile(filename, frameCache);
if (selectedNameFilter == filters[24]) result = loadWiresharkFile(filename, frameCache);
progress.cancel();
@@ -305,6 +308,16 @@ bool FrameFileIO::autoDetectLoadFile(QString filename, QVector<CANFrame>* frames
}
}
qDebug() << "Attempting Wireshark Log";
if (isWiresharkFile(filename))
{
if (loadWiresharkFile(filename, frames))
{
qDebug() << "Loaded as Wireshark Log successfully!";
return true;
}
}
qDebug() << "Attempting canalyzer ASC";
if (isCanalyzerASC(filename))
{
@@ -4825,3 +4838,86 @@ bool FrameFileIO::loadCANServerFile(QString filename, QVector<CANFrame>* frames)
delete inFile;
return !foundErrors;
}
bool FrameFileIO::loadWiresharkFile(QString filename, QVector<CANFrame>* frames)
{
pcap_t *pcap_data_file;
CANFrame thisFrame;
long long startTimestamp = 0;
long long timeStamp;
int lineCounter = 0;
bool foundErrors = false;
pcap_pkthdr packetHeader;
const char *packetData = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
thisFrame.setFrameType(QCanBusFrame::DataFrame);
QByteArray ba = filename.toLocal8Bit();
pcap_data_file = pcap_open_offline(ba.data(), errbuf);
if (!pcap_data_file) {
return false;
}
packetData = (const char*)pcap_next(pcap_data_file, &packetHeader);
while (packetData) {
lineCounter++;
if (lineCounter > 100)
{
qApp->processEvents();
lineCounter = 0;
}
timeStamp = packetHeader.ts.tv_sec * 1000000 + packetHeader.ts.tv_usec;
if (0 == startTimestamp)
{
startTimestamp = timeStamp;
}
timeStamp -= startTimestamp;
thisFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, timeStamp));
thisFrame.isReceived = true; // TODO: check if tx detection is possible
thisFrame.setFrameType(QCanBusFrame::DataFrame);
thisFrame.setFrameId((0xff & *(packetData+17)) << 8 | (0xff & *(packetData+16)));
if (thisFrame.frameId() <= 0x7FF) thisFrame.setExtendedFrameFormat(false);
else thisFrame.setExtendedFrameFormat(true);
thisFrame.bus = 0;
int numBytes = *(packetData+20);
QByteArray bytes(numBytes, 0);
if (thisFrame.payload().length() > 8) thisFrame.payload().resize(8);
for (int d = 0; d < numBytes; d++)
{
bytes[d] = *(packetData + 24 + d);
}
thisFrame.setPayload(bytes);
frames->append(thisFrame);
packetData = (const char*)pcap_next(pcap_data_file, &packetHeader);
}
pcap_close(pcap_data_file);
pcap_data_file = NULL;
return !foundErrors;
}
bool FrameFileIO::isWiresharkFile(QString filename)
{
pcap_t *pcap_data_file;
char errbuf[PCAP_ERRBUF_SIZE];
QByteArray ba = filename.toLocal8Bit();
pcap_data_file = pcap_open_offline(ba.data(), errbuf);
if (!pcap_data_file) {
return false;
}
pcap_close(pcap_data_file);
pcap_data_file = NULL;
return true;
}
+2
View File
@@ -53,6 +53,7 @@ public:
static bool loadTeslaAPFile(QString filename, QVector<CANFrame>* frames);
static bool loadCLX000File(QString filename, QVector<CANFrame>* frames);
static bool loadCANServerFile(QString filename, QVector<CANFrame>* frames);
static bool loadWiresharkFile(QString filename, QVector<CANFrame>* frames);
//functions that pre-scan a file to try to figure out if they could read it. Used to automatically determine
//file type and load it.
@@ -78,6 +79,7 @@ public:
static bool isTeslaAPFile(QString filename);
static bool isCLX000File(QString filename);
static bool isCANServerFile(QString filename);
static bool isWiresharkFile(QString filename);
static bool saveCRTDFile(QString, const QVector<CANFrame>*);
static bool saveNativeCSVFile(QString, const QVector<CANFrame>*);
+214
View File
@@ -0,0 +1,214 @@
#include <math.h>
#include "pcaplite.h"
#define MAGIC_NG 0x0A0D0D0A
#define MACIG 0xA1B2C3D4
#define MAX_CAN_PACKET_SIZE 256
// some pcap format constants
#define PCAP_FILE_HEADER_LENGTH 24
#define PCAP_FRAME_HEADER_LENGTH 16
#define PCAP_CAP_FRAME_LENGTH_OFFSET 8
#define PCAP_FRAME_LENGTH_OFFSET 12
// some pcapng format constants
#define INTERFACE_DESCRITION_BLOCK 0x01
#define ENCHANCED_PACKET_BLOCK 0x06
static unsigned char pcap_buffer[MAX_CAN_PACKET_SIZE];
static pcap_t p;
pcap *pcap_open_offline(const char *filename, char *error_text) {
FILE *file;
snprintf(error_text, PCAP_ERRBUF_SIZE, "OK");
file = fopen(filename,"rb");
if (NULL == file) {
snprintf(error_text, PCAP_ERRBUF_SIZE,
"Cannot open input file");
return NULL;
}
unsigned int magic;
size_t bytes_read;
bytes_read = fread(&magic, 1, sizeof(magic), file);
if (bytes_read != sizeof(magic)) {
snprintf(error_text, PCAP_ERRBUF_SIZE, "Cannot read magic word");
fclose(file);
return (NULL);
}
if (magic != MACIG && magic != MAGIC_NG) {
snprintf(error_text, PCAP_ERRBUF_SIZE, "Not a supported format %04x", magic);
fclose(file);
return (NULL);
}
// set the format
// and seek past file header
if (MAGIC_NG == magic) {
p.is_ng = 1;
fseek(file, sizeof(magic), SEEK_SET);
unsigned int section_length;
bytes_read = fread(&section_length, 1, sizeof(section_length), file);
if (bytes_read != sizeof(section_length)) {
snprintf(error_text, PCAP_ERRBUF_SIZE, "Cannot read section length");
fclose(file);
return (NULL);
}
fseek(file, section_length, SEEK_SET);
} else {
p.is_ng = 0;
fseek(file, PCAP_FILE_HEADER_LENGTH, SEEK_SET);
}
p.file = file;
return(&p);
}
const unsigned char *pcap_next_ng(pcap_t *p, struct pcap_pkthdr *h) {
// this is for ENCHANCED_PACKET_BLOCK
struct block_header {
unsigned int block_type;
unsigned int block_size;
unsigned int interface_id;
unsigned int timestamp_hi;
unsigned int timestamp_lo;
unsigned int cap_len;
unsigned int len;
} bh;
struct option_header {
unsigned short option_type;
unsigned short option_length;
} oh;
size_t bytes_read;
static double timestamp_multiplier = 0.000001; //microseconds resolution
long fpos = ftell(p->file);
do {
bytes_read = fread(&bh, 1, sizeof(bh), p->file);
if (bytes_read != sizeof(bh)) {
//probably EOF
return (NULL);
}
if (bh.block_type != ENCHANCED_PACKET_BLOCK) {
if (INTERFACE_DESCRITION_BLOCK == bh.block_type) {
// Seek to start of options part in the header
fseek(p->file, fpos + 16, SEEK_SET);
do {
bytes_read = fread(&oh, 1, sizeof(oh), p->file);
if (bytes_read != sizeof(oh)) {
//probably EOF
return (NULL);
}
// calcualte option length aligned on 4 byte boundary
unsigned int option_file_length = 4*(oh.option_length/4) + ((oh.option_length%4) ? 4:0);
// read in the buffer if it's large enough or skip
if (option_file_length <= sizeof(pcap_buffer)) {
bytes_read = fread(pcap_buffer, 1, option_file_length, p->file);
if (bytes_read != option_file_length) {
//probably EOF
return (NULL);
}
//check if time resolution option
if (0x09 == oh.option_type) {
unsigned int res = *(unsigned int*)pcap_buffer;
if ((0x80000000 & res) == 0) {
timestamp_multiplier = 1/pow(10, res);
} else {
timestamp_multiplier = 1/pow(2, (res & 0x7fffffff));
}
}
} else if (fseek(p->file, option_file_length, SEEK_CUR)) {
//probably EOF
return (NULL);
}
} while(ftell(p->file) < fpos + bh.block_size - sizeof(bh.block_size));
if (fseek(p->file, sizeof(bh.block_size), SEEK_CUR)) {
//probably EOF
return (NULL);
}
}
// skip to the next block
if (fseek(p->file, fpos + bh.block_size, SEEK_SET)) {
//probably EOF
return (NULL);
}
fpos = ftell(p->file);
}
} while (bh.block_type != ENCHANCED_PACKET_BLOCK);
h->caplen = bh.cap_len;
double timestamp = ((unsigned long long)bh.timestamp_hi << 32 | bh.timestamp_lo) * timestamp_multiplier;
double fractional, integer;
fractional = modf(timestamp, &integer);
h->ts.tv_sec = (long)integer;
h->ts.tv_usec = (long)(fractional * 1000000);
bytes_read = fread(pcap_buffer, 1, h->caplen, p->file);
if (bytes_read != h->caplen) {
//probably EOF
return (NULL);
}
//seek to the next block (go back with bytes read of the block and seek fwd with the block size)
if (fseek(p->file, fpos + bh.block_size, SEEK_SET)) {
//probably EOF
return (NULL);
}
return pcap_buffer;
}
const unsigned char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)
{
if (p->is_ng) {
return pcap_next_ng(p, h);
}
size_t bytes_read;
bytes_read = fread(pcap_buffer, 1, PCAP_FRAME_HEADER_LENGTH, p->file);
if (bytes_read != PCAP_FRAME_HEADER_LENGTH) {
//probably EOF
return (NULL);
}
h->ts.tv_sec = *(unsigned int*)(pcap_buffer);
h->ts.tv_usec = *(unsigned int*)(pcap_buffer + 4);
h->caplen = *(unsigned int*)(pcap_buffer + PCAP_CAP_FRAME_LENGTH_OFFSET);
h->len = *(unsigned int*)(pcap_buffer + PCAP_FRAME_LENGTH_OFFSET);
bytes_read = fread(pcap_buffer, 1, h->caplen, p->file);
if (bytes_read != h->caplen) {
//probably EOF
return (NULL);
}
return pcap_buffer;
}
void pcap_close(pcap_t *p) {
fclose(p->file);
}
+32
View File
@@ -0,0 +1,32 @@
#ifndef PCAPLITE_H
#define PCAPLITE_H
#include <stdio.h>
#if defined(unix) || defined __APPLE__
#include <sys/time.h>
#else
#include <winsock.h>
#endif
#define PCAP_ERRBUF_SIZE 256
struct pcap_pkthdr {
struct timeval ts; /* time stamp */
unsigned int caplen; /* length of portion present */
unsigned int len; /* length of this packet (off wire) */
};
struct pcap {
FILE *file;
bool is_ng;
};
typedef struct pcap pcap_t;
pcap *pcap_open_offline(const char *, char *);
const unsigned char *pcap_next(pcap_t *, struct pcap_pkthdr *);
void pcap_close(pcap_t *);
#endif// PCAPLITE_H