Description
I’m writing a High-Level Analyzer for a CAN-based protocol (Varex) where a single logical message can be split across multiple packets, and packets from different messages can be interleaved on the bus.
The screenshot below (you can see it in the attachment) shows the situation:
-
There is a header + payload (Packet 1) of Message A
-
Then the header of Message B appears in the middle
-
Then the payload (Packet 2) of Message A continues after that
Some messages consist only of a header with no payload. Others have a payload with multiple fields, and some values are 4-byte floats spanning several bytes.
From a protocol-parsing perspective, the natural thing to do is:
-
Accumulate all bytes for one logical message into an array of bytes (regardless of how many CAN packets it is split into, and even if those packets are interleaved with other messages).
-
Once the full message is received, parse the byte array into values (including multi-byte fields, floats, etc.).
-
Emit the corresponding
AnalyzerFrames for those values after the message is fully known.
This is much simpler than trying to keep state per individual byte or packet and emitting frames as bytes arrive.
Problem: timestamp monotonicity & interleaving
The issue is that the High-Level Analyzer framework enforces strictly increasing timestamps per frame type. If I try to implement the “buffer then emit” approach, I hit the following error:
CanVarexAnalyzer error - Invalid begin time for frame type 'xyz', begin must start after the previous frame.
Here’s a concrete example of what happens:
-
While decoding, I emit a
messageframe for the header of Message B, which appears between packet 1 and packet 2 of Message A, because this message is a simple message with only the header, and thus can be treated right away, without waiting for the payload to come. -
Later, once I have collected all bytes of Message A, I want to emit value frames for Message A using the original timestamps of the bytes, which are slightly earlier because those bytes came from packet 1 that was on the wire before the header of Message B.
-
When I emit these frames with earlier timestamps than the already-emitted header frame, Logic 2 raises the “Invalid begin time” error.
From the protocol’s point of view, this is legitimate: I’m simply adding more semantic information about earlier packets once I have seen the complete message. I am not overlapping times (the new frames still sit in gaps of time that are not already covered by other frames); I just need to go “back in time” slightly for ordering.
Why the current behavior is limiting
-
Treating bytes strictly “as they come” and forcing all
AnalyzerFrames to be emitted in real-time order makes complex parsers much harder. -
For messages with multi-byte values (e.g. 4-byte floats) split across interleaved packets, I need to track state across bytes and packets, and emit partial or placeholder frames before I actually have all data. That is error-prone and much harder to maintain.
-
The more natural approach—buffering bytes for one logical message, then parsing and emitting frames when it is complete—is effectively blocked by the timestamp monotonicity requirement.
-
I tried another workaround: buffer all
AnalyzerFrames in a list, sort them by timestamp at the end, and then emit them in order. But theHighLevelAnalyzerAPI only provides__init__anddecode. There is no “end-of-capture” or “finalize” callback where I can know that all frames have been seen and safely flush/sort the buffered frames.
Because of this combination (strict per-type timestamp monotonicity + no finalize hook), some protocols with interleaved, multi-packet messages are very hard or impossible to implement cleanly.
Expected / Desired Behavior
It would be extremely helpful if at least one of the following were supported:
-
Relaxed timestamp rule:
Allow a frame’sstart_timeto go backward as long as it does not overlap with an existing frame of the same type. In other words, reject overlaps, not merely non-monotonicity. This would allow analyzers to emit semantic frames later, using earlier timestamps, without breaking other frames. -
End-of-capture / finalize hook:
Add a method such as:def finalize(self): # called once after all frames have been passed to decode() ...so that:
-
I can buffer
AnalyzerFrames duringdecode(), -
Sort them by timestamp in
finalize(), -
And then return them all in correct chronological order.
-
-
Official support for buffering + sorted emission:
For example, allowingdecode()to return an empty list while buffering internally, and then a dedicated way for Logic 2 to ask the analyzer for “any remaining frames” at the end.
Summary
Because my protocol allows interleaved packets from multiple messages, and because I need to parse multi-byte values across packets, the most robust pattern is:
- Buffer bytes per logical message → parse whole message → emit semantic frames after the fact.
The current High-Level Analyzer behavior (strict start_time monotonicity and no finalize hook) makes this pattern very difficult and leads to errors like:
Invalid begin time for frame type 'xyz', begin must start after the previous frame.
Relaxing the timestamp constraint to focus on overlaps instead of strictly increasing order, or providing a finalize mechanism, would greatly improve the flexibility of the HLA API and make it much easier to support complex, interleaved protocols like this one.
Thanks for considering this — I think such a change would help a lot of analyzer authors dealing with real-world bus traffic where messages are not nicely isolated or strictly sequential.
Here is a photo showing what I have described:
