CANtrip Architecture

CANtrip

How it's built: an architecture walkthrough

v1.5.0 - Yukari · Qt 6 · C++20 · GPLv3
0:00 / 2:58

    Every code panel is quoted from the CANtrip v1.5.0 source, lightly trimmed where marked. The incidents are real bugs found and fixed on real hardware.

    Transcript
    1. How CANtrip is built. Processes, interfaces, wire formats and the decisions behind them.
    2. Windows has no SocketCAN. On Linux every adapter is a network interface behind one kernel API; on Windows every vendor ships its own DLL. The goals: don't write a capture stack, don't write a frame parser, keep every vendor behind one interface.
    3. Three processes, three channels. cantrip.exe starts tshark, tshark starts can2pcap.exe as an extcap. Frames travel as pcap records through a fifo and come back as JSON on stdout. can2pcap owns the hardware handle; transmit goes through a named pipe on PEAK or a second port on Vector.
    4. One interface, any vendor. IAvlabsCanBackend has initialize, uninitialize, a non-blocking readFrame and writeFrame. Each backend loads its vendor DLL at runtime, so a missing DLL just hides that vendor's channels.
    5. Vendor struct in, pcap record out. can2pcap's loop reads a frame and writes a 16-byte SocketCAN record (72 for CAN FD) in network byte order under LINKTYPE 227. The FD DLC code becomes a byte length here. Incident: frames once lost their tail because the raw code was written as the length.
    6. Wireshark does the parsing. tshark -T ek emits one JSON object per frame; TsharkCapture reads the can or canfd layer and data_data_data into a DecodedCanFrame. Gotcha: AUTOSAR NM matches ID 0, so tshark runs with that dissector disabled.
    7. Every frame takes the same path. Capture, your own transmits and replay all feed onFrameReceived. Logging sees every frame first; the display is throttled to the display rate. BusLoadTracker taps the capture directly and ignores replay. Incident: the UI froze on a busy bus until the throttle existed.
    8. DLC code or byte count? Above 8, FD DLC codes map to 12 to 64 bytes. CANtrip converts at three boundaries. Incident: a byte count of 64 sent as a DLC code caused bus errors and a crash on a Vector adapter.
    9. Sending while capturing. Vector allows a second port with a zero permission mask. PCAN-Basic refuses a second initialization, so frames go through a named pipe to can2pcap, which writes on its own handle. Incident: opening the port at capture start killed PEAK captures, so it now opens on the first send.
    10. Bus load, bit by bit. Each frame is costed in bits with a stuffing factor and timed at the right bitrate, then aggregated over a rolling one-second window and graphed through the existing Graph view.
    11. Runes: JSON that tolerates absence. No version field: a missing key gets its default, the graph layout migrates by shape, and the trace header is Qt's own saved state.
    12. Same classes, no widgets. main.cpp checks for --headless before creating any Qt application; QCoreApplication and HeadlessRunner reuse the plain classes. Ctrl+C sets a flag that a 200 ms timer reads on the main thread.
    13. Design rules. Reuse proven parts, one interface per vendor, plain non-GUI classes, one path for every frame, tolerate absence.