as

DoIP to CAN TP Gateway - Routing Matrix Generation and Host Demo

Table of Contents

  1. Introduction
  2. The Diagnostic Routing Table Model
  3. Gateway Network Configuration
  4. Runtime Routing Behavior
  5. Simulating Edge CAN TP Nodes
  6. Host Demo

1. Introduction

A central gateway connects the DoIP diagnostic tester on Ethernet to many edge ECUs distributed over several CAN/CAN FD buses. The diagnostic routing is usually maintained by system engineers in a diagnostic routing table. AS provides:

This document explains the routing table model, gateway configuration, and runtime data flow using typical fictionalized examples. The corresponding example configuration files are located in app/app/config/DoIPGW/.

2. The Diagnostic Routing Table Model

2.1 Table Layout

Each row describes one routing rule and is split into a DoIP side and a CAN side:

Side Meaning
DoIP side Tester Source, tester DoIP SA (source logical address), DoIP TA (target logical address)
CAN side Target bus, CAN request/response Message ID, optional DoIP SA/TA
Meta Gateway ECU, comment, change record

The table has two sections with mirrored column semantics:

2.2 Typical Request Table

Example: Tester SA 0x0E80, functional group TA 0xE001, and three physical ECUs.

DoIP SA DoIP TA Target bus CAN request ID Comment
0x0E80 0xE001 PT_CANFD 0x7E0 Functional group (fan-out to CAN FD)
0x0E80 0xE001 CL1_CAN 0x7DF Functional group (classic CAN functional ID)
0x0E80 0x004A PT_CANFD 0x731 ECU_A, physical
0x0E80 0x0053 BD_CANFD 0x741 ECU_B, physical
0x0E80 0x0757 CL1_CAN 0x757 ECU_C, physical (11-bit ID)

Rules:

A second section typically lists remote/OTA testers with different SAs (e.g. 0x0F00) and their own functional groups routed to different bus subsets. Each tester SA corresponds to one tester/routine pair in the DoIP configuration.

2.3 Typical Response Table

Source bus CAN response ID DoIP SA DoIP TA Comment
PT_CANFD 0x732 0x004A 0x0E80 ECU_A → tester
BD_CANFD 0x742 0x0053 0x0E80 ECU_B → tester
CL1_CAN 0x75F 0x0757 0x0E80 ECU_C → tester

The response table derives each node’s CAN RX ID at the gateway (gateway receives responses on 0x732 and sends requests on 0x731). Functional groups have no response rows: functional UDS requests are normally sent with the response-suppression bit set, so edge nodes do not respond.

3. Gateway Network Configuration

The example configuration files are located in app/app/config/DoIPGW/:

File Content
Network.json DoIP: discovery address, max_connections, targets (physical + functional group), routines, testers
PduR.json PduR gateway routes: _RX/_TX per node; functional target includes destinations fan-out and DestBuffer
CanTp.json One CanTp channel per node; LL_DL = 64 for CAN FD, 8 for classic CAN
CanIf.json CAN IDs: TX PDU = request ID, RX PDU = response ID, all 11-bit standard IDs
Mempool.json Memory pool used by SoAd/DoIP

3.1 CanIf and CanTp PDU Direction Explanation

In the PduR configuration for this gateway, PDU routing paths use the naming convention where _RX denotes the direction “from tester to ECU” (request path) and _TX denotes “from ECU to tester” (response path). The CanTp configuration must align with PduR’s PDU IDs.

Looking at the generated code (e.g. CanTp_Cfg.c and PduR_Cfg.h):

Also mapping to CanIf: the request that CanTp sends to the bus goes via CANIF_<name>_TX (defined in CanIf as the gateway TX frame on the bus). The responses received from the bus come in via the corresponding CanIf RX frame and are delivered to CanTp. In the JSON, we see RxPduId in CanTp points to the CanIf TX PDU name (e.g. PT_CANFD_E001_TX) and TxPduId points to the CanIf RX PDU name (e.g. PT_CANFD_E001_RX). This matches the generator’s mapping: CanIfTxPduId = CANIF_<name>_TX, and PduR_RxPduId/PduR_TxPduId are taken from RxPduId/TxPduId in the JSON (mapped to PDUR_* in the generated config).

So for gateway forwarding (DoIP → CAN):

In this configuration, the JSON fields are mapped by the generator as follows (see tools/generator/CanTp.py):

The key point is that the naming is consistent with the generated PduR/CanTp configuration; RxPduId in the JSON is used to derive the PduR ID that CanTp uses for its PduR interface, not directly the bus RX name. For functional group channels, the corresponding response-side PDU is typically unused due to response suppression, but TxPduId is still specified to maintain a uniform channel structure.

3.2 Configuration Notes

4. Runtime Routing Behavior

graph TB
    T["DoIP Tester SA 0x0E80"]
    D["DoIP"]

    subgraph TX["TX Paths"]
        PTX["PduR node_TX"]
        RA["CanIf+CanTp RX 0x732"]
        RB["CanIf+CanTp RX 0x742"]
        RC["CanIf+CanTp RX 0x75F"]
    end

    subgraph BUS["CAN Bus"]
        direction TB
        EA["Edge ECU_A"]
        EB["Edge ECU_B"]
        EC["Edge ECU_C"]
    end

    subgraph RX["RX Paths"]
        direction TB
        PA["CanTp+CanIf ECU_A 0x731"]
        PB["CanTp+CanIf ECU_B 0x741"]
        PC["CanTp+CanIf ECU_C 0x757"]
        PF["CanTp+CanIf Func 0x7E0 0x7DF"]
        PRX["PduR node_RX"]
    end

    T --> D
    D --> PRX
    PRX --> PA
    PRX --> PB
    PRX --> PC
    PRX --> PF
    PA --> EA
    PB --> EB
    PC --> EC
    PF -- "Function Address" --> BUS
    EA --> RA
    EB --> RB
    EC --> RC
    RA --> PTX
    RB --> PTX
    RC --> PTX
    PTX --> D
    D --> T

5. Simulating Edge CAN TP Nodes

dummy_ecu.py uses the host simulator binding one.AsPy.isotp. Each ECU runs in its own process. The ID orientation is from the ECU’s perspective:

5.1 Edge Node and CAN ID Mapping

Simulated node rxid (requests in) txid (responses out) LL_DL
ECU_A (PT_CANFD) 0x731 0x732 64
ECU_B (BD_CANFD) 0x741 0x742 64
ECU_C (CL1 classic CAN) 0x757 0x75F 8
Functional listener (FD) 0x7E0 - (no response) 64
Functional listener (classic CAN) 0x7DF - (no response) 8

The functional listener nodes do not need to be started in the demo: functional UDS requests always set the positive-response-suppression bit, so no simulated ECU needs to respond. You only observe the gateway fanning the request out to 0x7E0 and 0x7DF.

5.2 Dummy Responder

dummy_ecu.py simulates one ECU per process (no threading). It accepts --rxid, --txid, --ll-dl, and --name as command-line arguments. Response logic: for every request, it returns the positive service ID (SID | 0x40) and echoes the remaining bytes. For 0x10 (SessionControl), it appends the standard P2/P2* timing bytes 00 32 01 F4 (P2=50ms, P2*=5s).

Example startup:

python app/app/config/DoIPGW/dummy_ecu.py --rxid 0x731 --txid 0x732 --ll-dl 64 --name ECU_A
python app/app/config/DoIPGW/dummy_ecu.py --rxid 0x741 --txid 0x742 --ll-dl 64 --name ECU_B
python app/app/config/DoIPGW/dummy_ecu.py --rxid 0x757 --txid 0x75F --ll-dl 8  --name ECU_C

5.3 DoIP Tester

Use the DoIPSend command-line tool (build with scons --app=DoIPSend, binary at build\nt\GCC\DoIPSend\DoIPSend.exe) to send diagnostic requests. It performs vehicle discovery, TCP connection, and routing activation, sends a single UDS request, and prints the response. Key options: -v UDS request as a hex string, -s tester SA, -t target TA, -i/-p discovery address and port.

Examples:

# Physical request to ECU_A (TA 0x004A), UDS 10 01
build\nt\GCC\DoIPSend\DoIPSend.exe -v 1001 -s 0x0E80 -t 0x004A

# Physical request to ECU_C (TA 0x0757), UDS 10 01
build\nt\GCC\DoIPSend\DoIPSend.exe -v 1001 -s 0x0E80 -t 0x0757

# Functional request (TA 0xE001), UDS 28 83 03 (positive response suppressed), no UDS response
build\nt\GCC\DoIPSend\DoIPSend.exe -v 288303 -s 0x0E80 -t 0xE001

6. Host Demo

Follow the steps below to run the DoIP-to-CAN gateway demo on a host and observe CAN bus traffic with CanDump. You need four components: the gateway DoIPGW, CAN sniffer CanDump, DoIP client DoIPSend, and the edge ECU simulation script dummy_ecu.py.

Before running, ensure MSYS2 mingw64\bin and build\nt\GCC\one are in your PATH.

Step 1 - Build

scons --app=DoIPGW      # Gateway
scons --app=CanDump     # CAN sniffer
scons --app=DoIPSend    # DoIP tester client

Build artifacts:

Tool Path
Gateway build\nt\GCC\DoIPGW\DoIPGW.exe
CAN sniffer build\nt\GCC\one\CanDump.exe
DoIP client build\nt\GCC\DoIPSend\DoIPSend.exe

Step 2 - Start the Gateway (Shell 1)

build\nt\GCC\DoIPGW\DoIPGW.exe

The gateway opens DoIP UDP/TCP port 13400 and activates the line.

Step 3 - Start the CAN Bus Sniffer (Shell 2)

build\nt\GCC\one\CanDump.exe -d simulator_v2 -p 0

CanDump attaches to the same simulator_v2 virtual CAN bus as the gateway and prints all CAN frames in real time.

Step 4 - Start the Edge ECUs (Shell 3+)

python app/app/config/DoIPGW/dummy_ecu.py --rxid 0x731 --txid 0x732 --ll-dl 64 --name ECU_A
python app/app/config/DoIPGW/dummy_ecu.py --rxid 0x741 --txid 0x742 --ll-dl 64 --name ECU_B
python app/app/config/DoIPGW/dummy_ecu.py --rxid 0x757 --txid 0x75F --ll-dl 8  --name ECU_C

Each process listens for requests on rxid and replies on txid.

Step 5 - Send Requests and Observe CAN Frames

Use DoIPSend to send requests. The CanDump window displays the request frame forwarded by the gateway to the CAN bus and the response frame returned by the ECU.

Scenario 1: Physical request to ECU_A (TA 0x004A), UDS 10 01

build\nt\GCC\DoIPSend\DoIPSend.exe -v 1001 -s 0x0E80 -t 0x004A

CanDump output:

canid=00000731,dlc=08,data=[02,10,01,55,55,55,55,55,] [...UUUUU] @ 0.808733 s rel 0.00 ms
canid=00000732,dlc=08,data=[06,50,01,00,32,01,F4,55,] [P.2.U] @ 0.812000 s rel 3.27 ms

Scenario 2: Physical request to ECU_C (TA 0x0757, classic CAN), UDS 10 01

build\nt\GCC\DoIPSend\DoIPSend.exe -v 1001 -s 0x0E80 -t 0x0757
canid=00000757,dlc=08,data=[02,10,01,55,55,55,55,55,] [...UUUUU] @ 7.120599 s rel 0.00 ms
canid=0000075F,dlc=08,data=[06,50,01,00,32,01,F4,55,] [P.2.U] @ 7.124000 s rel 3.40 ms

Classic CAN uses 8-byte frames; PCI and data format are the same as for FD nodes.

Scenario 3: Functional request (TA 0xE001), UDS 28 83 03 (positive response suppressed)

build\nt\GCC\DoIPSend\DoIPSend.exe -v 288303 -s 0x0E80 -t 0xE001
canid=000007E0,dlc=08,data=[03,28,83,03,55,55,55,55,] [.(..UUUU] @ 13.416609 s rel 0.00 ms
canid=000007DF,dlc=08,data=[03,28,83,03,55,55,55,55,] [.(..UUUU] @ 13.417583 s rel 0.97 ms

The gateway replicates the functional request to two functional CAN IDs: 0x7E0 (FD functional node) and 0x7DF (classic CAN functional node). Since the positive-response-suppression bit is set, edge nodes do not respond; only request frames appear.

6.2 CAN ID Reference Table

Direction CAN ID PDU name Description
Gateway → ECU_A 0x731 PT_CANFD_004A_TX Request to ECU_A
ECU_A → Gateway 0x732 PT_CANFD_004A_RX Response from ECU_A
Gateway → ECU_B 0x741 BD_CANFD_0053_TX Request to ECU_B
ECU_B → Gateway 0x742 BD_CANFD_0053_RX Response from ECU_B
Gateway → ECU_C 0x757 CL1_0757_TX Request to ECU_C (classic CAN)
ECU_C → Gateway 0x75F CL1_0757_RX Response from ECU_C (classic CAN)
Gateway → Functional (FD) 0x7E0 PT_CANFD_E001_TX Functional fan-out (FD)
Gateway → Functional (classic CAN) 0x7DF CL1_E001_TX Functional fan-out (classic CAN)