From 5313faff69221b367f25373c39046b22d17e175d Mon Sep 17 00:00:00 2001 From: Tomasz Dobrowolski Date: Wed, 18 Mar 2026 11:32:11 +0100 Subject: [PATCH 1/5] Fix LAWICELL timestamping bug --- connections/lawicel_serial.cpp | 34 +++++++++++++++++++++------------- connections/lawicel_serial.h | 2 -- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/connections/lawicel_serial.cpp b/connections/lawicel_serial.cpp index 1be4eb3..320f4d9 100644 --- a/connections/lawicel_serial.cpp +++ b/connections/lawicel_serial.cpp @@ -474,8 +474,6 @@ void LAWICELSerial::readSerialData() QByteArray data; unsigned char c; QString debugBuild; - CANFrame buildFrame; - QByteArray buildData; if (serial) data = serial->readAll(); @@ -491,40 +489,50 @@ void LAWICELSerial::readSerialData() { qDebug() << "Got CR!"; + CANFrame buildFrame; + QByteArray buildData; + if (useSystemTime) { buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul)); } else { + bool isFD = false; char offset; char len_index; switch(mBuildLine[0].toLatin1()) { - case 't': + case 'b': case 'd': + isFD = true; + [[fallthrough]]; + case 't': offset = 5; len_index = 4; - break; - case 'T': + break; + case 'B': case 'D': + isFD = true; + [[fallthrough]]; + case 'T': offset = 10; len_index = 9; - break; + break; default: offset = 5; len_index = 4; - break; + break; } - //If total length is greater than command, header and data, timestamps must be enabled. - if (data.length() > (offset + mBuildLine.mid(len_index, 1).toInt() * 2 + 1)) + int dlc = mBuildLine.mid(len_index, 1).toInt(); + int byteCount = isFD ? (int)dlc_code_to_bytes(dlc) : dlc; + int frameStringLen = offset + byteCount * 2; + bool hasTimestamp = mBuildLine.length() > frameStringLen + 1; + if (hasTimestamp) { - //Four bytes after the end of the data bytes. - buildTimestamp = mBuildLine.mid(offset + mBuildLine.mid(len_index, 1).toInt() * 2, 4).toInt(nullptr, 16); - buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, buildTimestamp)); + buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, mBuildLine.mid(frameStringLen, 4).toInt(nullptr, 16) * 1000l)); } else { - //Default to system time if timestamps are disabled. buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul)); } } diff --git a/connections/lawicel_serial.h b/connections/lawicel_serial.h index cfee96d..d16e1f6 100644 --- a/connections/lawicel_serial.h +++ b/connections/lawicel_serial.h @@ -60,8 +60,6 @@ protected: bool isAutoRestart; QSerialPort *serial; int framesRapid; - CANFrame buildFrame; - qint64 buildTimestamp; bool can0Enabled; bool can0ListenOnly; bool canFd; From 1483aab2a7ec1c6a7d8889887c686fbca7ada0ed Mon Sep 17 00:00:00 2001 From: Tomasz Dobrowolski Date: Wed, 18 Mar 2026 12:36:22 +0100 Subject: [PATCH 2/5] fix timestamp rollover --- connections/lawicel_serial.cpp | 24 +++++++++++++++++++++++- connections/lawicel_serial.h | 4 ++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/connections/lawicel_serial.cpp b/connections/lawicel_serial.cpp index 320f4d9..bcb4a48 100644 --- a/connections/lawicel_serial.cpp +++ b/connections/lawicel_serial.cpp @@ -17,6 +17,7 @@ LAWICELSerial::LAWICELSerial(QString portName, int serialSpeed, int lawicelSpeed serial = nullptr; isAutoRestart = false; + rebuildLocalTimeBasis(); readSettings(); } @@ -203,6 +204,14 @@ bool LAWICELSerial::piSendFrame(const CANFrame& frame) /****************************************************************/ +void LAWICELSerial::rebuildLocalTimeBasis() +{ + timeBasis = 0; + lastHWTimestamp = -1; + wrapAdder = 0; + lastSysMs = 0; +} + void LAWICELSerial::readSettings() { QSettings settings; @@ -254,6 +263,8 @@ void LAWICELSerial::deviceConnected() { sendDebug("Connecting to LAWICEL Device!"); + rebuildLocalTimeBasis(); + QByteArray output; output.clear(); @@ -529,7 +540,18 @@ void LAWICELSerial::readSerialData() bool hasTimestamp = mBuildLine.length() > frameStringLen + 1; if (hasTimestamp) { - buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, mBuildLine.mid(frameStringLen, 4).toInt(nullptr, 16) * 1000l)); + qint64 hwTs = mBuildLine.mid(frameStringLen, 4).toInt(nullptr, 16); + qint64 sysMs = QDateTime::currentMSecsSinceEpoch(); + if (lastHWTimestamp >= 0 && hwTs < lastHWTimestamp) { + qint64 sysDelta = sysMs - lastSysMs; + wrapAdder += lastHWTimestamp + sysDelta - hwTs; + } + lastHWTimestamp = hwTs; + lastSysMs = sysMs; + qint64 unwrappedMs = wrapAdder + hwTs; + if (timeBasis == 0) + timeBasis = sysMs - unwrappedMs; + buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds((timeBasis + unwrappedMs) * 1000)); } else { diff --git a/connections/lawicel_serial.h b/connections/lawicel_serial.h index d16e1f6..d137fcc 100644 --- a/connections/lawicel_serial.h +++ b/connections/lawicel_serial.h @@ -60,6 +60,10 @@ protected: bool isAutoRestart; QSerialPort *serial; int framesRapid; + qint64 timeBasis; + qint64 lastHWTimestamp; + qint64 wrapAdder; + qint64 lastSysMs; bool can0Enabled; bool can0ListenOnly; bool canFd; From 5e3d6a305d75266fbd0a9db3142e3f63eee42dcb Mon Sep 17 00:00:00 2001 From: Tomasz Dobrowolski Date: Wed, 18 Mar 2026 13:08:26 +0100 Subject: [PATCH 3/5] another fix --- connections/lawicel_serial.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/connections/lawicel_serial.cpp b/connections/lawicel_serial.cpp index bcb4a48..4ed6c35 100644 --- a/connections/lawicel_serial.cpp +++ b/connections/lawicel_serial.cpp @@ -505,7 +505,7 @@ void LAWICELSerial::readSerialData() if (useSystemTime) { - buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul)); + buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ll)); } else { @@ -551,11 +551,11 @@ void LAWICELSerial::readSerialData() qint64 unwrappedMs = wrapAdder + hwTs; if (timeBasis == 0) timeBasis = sysMs - unwrappedMs; - buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds((timeBasis + unwrappedMs) * 1000)); + buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, (timeBasis + unwrappedMs) * 1000ll)); } else { - buildFrame.setTimeStamp(QCanBusFrame::TimeStamp::fromMicroSeconds(QDateTime::currentMSecsSinceEpoch() * 1000ul)); + buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ll)); } } From ee3e2e27123e799c66f3078b0135f3e81b47ab41 Mon Sep 17 00:00:00 2001 From: Tomasz Dobrowolski Date: Wed, 18 Mar 2026 13:21:54 +0100 Subject: [PATCH 4/5] cleanup --- connections/lawicel_serial.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/connections/lawicel_serial.cpp b/connections/lawicel_serial.cpp index 4ed6c35..89cd27f 100644 --- a/connections/lawicel_serial.cpp +++ b/connections/lawicel_serial.cpp @@ -503,11 +503,8 @@ void LAWICELSerial::readSerialData() CANFrame buildFrame; QByteArray buildData; - if (useSystemTime) - { - buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ll)); - } - else + buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ll)); + if (!useSystemTime) { bool isFD = false; char offset; @@ -537,8 +534,7 @@ void LAWICELSerial::readSerialData() int dlc = mBuildLine.mid(len_index, 1).toInt(); int byteCount = isFD ? (int)dlc_code_to_bytes(dlc) : dlc; int frameStringLen = offset + byteCount * 2; - bool hasTimestamp = mBuildLine.length() > frameStringLen + 1; - if (hasTimestamp) + if (mBuildLine.length() > frameStringLen + 1) { qint64 hwTs = mBuildLine.mid(frameStringLen, 4).toInt(nullptr, 16); qint64 sysMs = QDateTime::currentMSecsSinceEpoch(); @@ -553,10 +549,6 @@ void LAWICELSerial::readSerialData() timeBasis = sysMs - unwrappedMs; buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, (timeBasis + unwrappedMs) * 1000ll)); } - else - { - buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, QDateTime::currentMSecsSinceEpoch() * 1000ll)); - } } switch (mBuildLine[0].toLatin1()) From 5fa1bb43ef290640418c7d247fa1b430f785d83f Mon Sep 17 00:00:00 2001 From: Tomasz Dobrowolski Date: Thu, 19 Mar 2026 11:59:31 +0100 Subject: [PATCH 5/5] simplify --- connections/lawicel_serial.cpp | 18 ++++++------------ connections/lawicel_serial.h | 1 - 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/connections/lawicel_serial.cpp b/connections/lawicel_serial.cpp index 89cd27f..cfd7d5a 100644 --- a/connections/lawicel_serial.cpp +++ b/connections/lawicel_serial.cpp @@ -209,7 +209,6 @@ void LAWICELSerial::rebuildLocalTimeBasis() timeBasis = 0; lastHWTimestamp = -1; wrapAdder = 0; - lastSysMs = 0; } void LAWICELSerial::readSettings() @@ -531,22 +530,17 @@ void LAWICELSerial::readSerialData() len_index = 4; break; } + int dlc = mBuildLine.mid(len_index, 1).toInt(); int byteCount = isFD ? (int)dlc_code_to_bytes(dlc) : dlc; int frameStringLen = offset + byteCount * 2; if (mBuildLine.length() > frameStringLen + 1) { - qint64 hwTs = mBuildLine.mid(frameStringLen, 4).toInt(nullptr, 16); - qint64 sysMs = QDateTime::currentMSecsSinceEpoch(); - if (lastHWTimestamp >= 0 && hwTs < lastHWTimestamp) { - qint64 sysDelta = sysMs - lastSysMs; - wrapAdder += lastHWTimestamp + sysDelta - hwTs; - } - lastHWTimestamp = hwTs; - lastSysMs = sysMs; - qint64 unwrappedMs = wrapAdder + hwTs; - if (timeBasis == 0) - timeBasis = sysMs - unwrappedMs; + qint64 hardwareMs = mBuildLine.mid(frameStringLen, 4).toInt(nullptr, 16); + if (lastHWTimestamp >= 0 && hardwareMs < lastHWTimestamp) { wrapAdder += 60000; } + lastHWTimestamp = hardwareMs; + qint64 unwrappedMs = wrapAdder + hardwareMs; + if (timeBasis == 0) { timeBasis = QDateTime::currentMSecsSinceEpoch() - unwrappedMs; } buildFrame.setTimeStamp(QCanBusFrame::TimeStamp(0, (timeBasis + unwrappedMs) * 1000ll)); } } diff --git a/connections/lawicel_serial.h b/connections/lawicel_serial.h index d137fcc..77c52c1 100644 --- a/connections/lawicel_serial.h +++ b/connections/lawicel_serial.h @@ -63,7 +63,6 @@ protected: qint64 timeBasis; qint64 lastHWTimestamp; qint64 wrapAdder; - qint64 lastSysMs; bool can0Enabled; bool can0ListenOnly; bool canFd;