Data Flow¶
How one CAN frame actually gets from a bit on the wire to a decoded signal on screen (or a logged line, or a plotted point):
sequenceDiagram
participant HW as CAN hardware
participant BE as IAvlabsCanBackend
participant CP as can2pcap.exe
participant TS as tshark -T ek
participant App as TsharkCapture (cantrip.exe)
participant MW as MainWindow
HW->>BE: raw frame (vendor SDK event)
BE->>CP: readFrame() -> CanFrame
CP->>CP: serializeFrame() -> SocketCAN pcap record
CP->>TS: written to fifo
TS->>TS: SocketCAN dissector decodes ID/DLC/data/FD flags
TS->>App: JSON (Elastic/ek output format), one object per frame
App->>App: parse -> DecodedCanFrame
App->>MW: frameReceived signal
MW->>MW: populateDecodedChildren() calls DbcDecoder::decodeSignals()
MW-->>MW: fan out to Trace view, Graph view (SignalHistoryStore), log writer
Where each responsibility actually lives¶
- Backend →
can2pcap.exe:readFrame()is documented and used as non-blocking - it returns immediately whether or not a frame arrived, andcan2pcap.exe's capture loop sleeps briefly when idle rather than blocking. See The AVlabs CAN Backend. can2pcap.exe: the only place that knows about the SocketCAN wire format. This is also where the CAN FD DLC-code-to-byte-length translation happens - see the note onCanFrame::dlcin The AVlabs CAN Backend.tshark: does the actual low-level frame dissection (ID/DLC/data/FD flags), using Wireshark's own built-in SocketCAN dissector. CANtrip never re-implements this.TsharkCapture(app/TsharkCapture.cpp): parsestshark's JSON output into aDecodedCanFrame- CANtrip's own in-process frame representation, distinct from the wire-levelCanFramestruct backends use.DbcDecoder(app/DbcDecoder.h/.cpp): DBC load + signal decode - a plain, non-GUI class (extracted out ofMainWindowspecifically so headless mode could reuse it without aMainWindowto host it).MainWindow: callsDbcDecoderfrompopulateDecodedChildren()and fans the result out to every view/writer that cares about it (Trace, Graph, log file) - the GUI-specific part (buildingQTreeWidgetItems, feedingSignalHistoryStore) is all that's left here now.
The transmit side feeds the same pipeline¶
MessageSender's frameSent signal connects
straight to the same onFrameReceived slot a live capture's
frameReceived signal does - a frame CANtrip itself transmits gets
logging, Trace/Graph display, and DBC decode entirely for free, with no
separate code path. It's marked as Tx-direction so it can be visually
distinguished (see Stimulation Tab),
but it flows through exactly the same machinery.
Replay feeds it too¶
LogReplaySource also connects to the same
onFrameReceived slot as TsharkCapture and MessageSender - see
Logging & Replay.