The PDU Router (PduR) in AUTOSAR manages communication between software modules (e.g., CanTp, Dcm, LinTp) by routing Protocol Data Units (PDUs) across the system. This document explains how to configure PduR networks, routines, memory pools, and buffers, leveraging JSON definitions and automated code generation.
PduR acts as a software router that:
Dcm <-> CanTp).CanTp <-> CanTp).Com and CanIf for physical bus communication (PduR itself does not handle hardware).CAN0, LIN0) for auto-generating routines from DBC files.The following module identifiers are used in from / to fields:
| Module | Type | Description |
|---|---|---|
CanIf |
Low Module | CAN Interface |
CanTp |
Transport Protocol (TP) | CAN Transport Protocol |
LinTp |
Transport Protocol (TP) | LIN Transport Protocol |
DoIP |
Transport Protocol (TP) | DoIP Transport Protocol |
J1939Tp |
Transport Protocol (TP) | J1939 Transport Protocol |
Dcm |
High Module | Diagnostic Communication Manager |
Com |
Low Module | Communication (Signal-based) |
OsekNm |
Network Management | OSEK Network Management |
CanNm |
Network Management | CAN Network Management |
PduR |
Router | PDU Router (self-reference) |
SecOC |
Security | Secure On-Board Communication |
Mirror |
Mirror | Mirror module for testing/observation |
TP Modules:
DoIP,CanTp,LinTp,J1939Tp- when bothfromandtoare TP modules, a gateway scenario is detected and gateway-specific code (buffering, copy functions) is generated.High Module:
Dcm- routes targeting Dcm are treated as high-priority diagnostic paths.Low Modules: TP modules +
CanIf- all other non-Dcm modules.
The following diagram shows how PduR sits at the center of the AUTOSAR communication stack, routing PDUs between upper-layer modules (Dcm, Com), security modules (SecOC), transport protocols (CanTp, LinTp, DoIP, J1939Tp), and bus interfaces (CanIf, LinIf). Mirror receives routed PDUs from PduR (PduR_MirrorTransmit) but transmits mirrored frames directly to CanIf/LinIf. CanNm and OsekNm bypass PduR entirely and communicate directly with CanIf.
flowchart TB
subgraph Upper["Upper Layer (Module > ISOTP)"]
DCM["Dcm"]
COM["Com"]
end
subgraph Security["Security Layer"]
SECOC["SecOC"]
end
subgraph RouterCenter["PDU Router"]
PR["PduR<br/>Routing Paths / Gateway Buffers / API Tables / MemPool"]
end
subgraph Transport["Transport Protocol (TP) Layer"]
CANTP["CanTp"]
LINTP["LinTp"]
DOIP["DoIP"]
J1939TP["J1939Tp"]
end
subgraph BusIF["Bus Interface Layer"]
CANIF["CanIf"]
LINIF["LinIf"]
end
subgraph NM["Network Management"]
CANNM["CanNm"]
OSEKNM["OsekNm"]
end
subgraph Other["Other"]
MIRROR["Mirror"]
end
DCM <--> PR
COM <--> PR
SECOC <--> PR
PR <---> CANTP
PR <---> LINTP
PR <---> DOIP
PR <---> J1939TP
PR <---> CANIF
PR <---> LINIF
MIRROR -.->|PduR_MirrorTransmit| PR
CANTP <---> CANIF
LINTP <---> LINIF
CANNM <--> CANIF
CANNM -.->|PduR_CanNmTriggerTransmit<br/>user data only| COM
OSEKNM <--> CANIF
MIRROR <---> CANIF
MIRROR <---> LINIF
Layer Boundary: The ISOTP boundary (Module > 8) separates upper-layer modules (Dcm, Com, SecOC, Mirror) from lower-layer modules (CanIf, CanTp, LinTp, DoIP, J1939Tp, CanNm, OsekNm). This boundary determines gateway forwarding behavior - upper-layer destinations receive data via TP callbacks, while lower-layer destinations receive data via direct Transmit.
{
"class": "PduR",
"routines": [
{
"name": "P2P_RX",
"from": "CanTp",
"to": "Dcm"
},
{
"name": "P2P_TX",
"from": "Dcm",
"to": "CanTp"
}
],
"networks": [
{
"name": "CAN0",
"network": "CAN",
"me": "AS",
"use_dbc": true,
"dbc": "CAN0.dbc",
"ignore": ["IGNORED_MSG"]
}
],
"memory": [
{
"name": "MyPool",
"size": 256,
"number": 2
}
],
"buffers": [
{
"name": "GwBuf",
"size": 4096
}
]
}
Routines define how PDUs are routed between modules. Each routine maps a PDU from a source module to one or more destination modules. The generator assigns each routine a unique index (macro PDUR_<name>) and generates source/destination Pdu structures.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | - | PDU name, referenced from EcuC.Pdus[].name. Used to generate PDUR_<name> macro. |
from |
string | Yes | - | Source module. Must be one of: CanIf, CanTp, OsekNm, CanNm, PduR, Dcm, Com, LinTp, DoIP, J1939Tp, SecOC, Mirror. |
to |
string | Yes | - | Destination module. Same enum as from. |
useDest |
bool | No | true |
Enable/disable the dest field. When false, the dest value is ignored and name is used as the destination PDU name. |
dest |
string | No | name |
Alternative destination PDU name. Only effective when useDest is true. When set, the destination PDU identifier uses this name instead of name. Both PDUR_<name> and PDUR_<dest> macros are generated. |
useDestBuffer |
bool | No | false |
Enable/disable gateway buffer configuration. When true, enables DestBufferType, DestBuffer, and DestBufferSize. |
DestBufferType |
string | No | private |
Type of gateway buffer: "private" allocates a dedicated buffer of size DestBufferSize; "shared" references a pre-defined buffer by DestBuffer name (from buffers[]). Only effective when useDestBuffer is true. |
DestBuffer |
string | No | - | Name of a pre-defined shared gateway buffer (from buffers[]) to use for this routine’s gateway data. Only effective when useDestBuffer is true and DestBufferType is "shared". |
DestBufferSize |
integer | No | 0 | Size of a dedicated private gateway buffer for this routine. When > 0 and useDestBuffer is true with DestBufferType "private", a private PduR_GwBuffer_<name> is allocated. |
useFake |
bool | No | true |
Enable/disable the fake field. When false, the fake value is ignored and no fake PDU macro is generated. |
fake |
string | No | - | Fake PDU name used for mirrored routing. Only effective when useFake is true. Generates an additional PDUR_<fake> macro pointing to the same index. |
destinations |
array | No | - | Additional destinations for multi-cast / mirror routing. Each entry can duplicate the PDU to other modules. |
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | - | Destination PDU name for this additional leg. |
to |
string | Yes | - | Destination module (same enum as routine to). Inherits from from the parent routine. |
useFake |
bool | No | false |
Enable/disable fake PDU name for this destination. |
fake |
string | No | - | Fake PDU name for mirrored routing on this destination leg. Only effective when the parent routine’s useFake is true. |
When both from and to (or any destinations[].to) are TP Modules (DoIP, CanTp, LinTp, J1939Tp), the generator:
hasGW = true, generating the PDUR_USE_TP_GATEWAY macro.PduR_BufferType structure for runtime gateway buffering.PduR_<Mod>GwStartOfReception, PduR_<Mod>GwCopyRxData, PduR_<Mod>GwRxIndication, etc.) for the involved modules.For gateway routines requiring data buffering, first enable gateway buffer configuration by setting useDestBuffer to true, then select the buffer type via DestBufferType:
DestBufferType = "private": Allocates a dedicated uint8_t PduR_GwBuffer_<name>[<DestBufferSize>] for this routine. Configure the size via DestBufferSize.DestBufferType = "shared": References a pre-defined buffer from buffers[] by name via DestBuffer.When useDestBuffer is false, no dedicated gateway buffer is used (NULL).
For each routine, the generator emits:
#define PDUR_<name> <index> - unique zero-based index for the routing path.PduR_SrcPdu_<from>_<to>_<name> - contains module ID, PDU ID, and API table pointer.PduR_DstPdu_<from>_<to>_<name>[] - array of destination Pdu entries.PduR_RoutingPaths[] table, linking source to destinations with optional gateway buffer.The following diagram illustrates the routing path data structure and how a source PDU fans out to multiple destinations:
flowchart LR
subgraph Src["Source (PduR_RoutingPathType)"]
SP["SrcPduRef<br/>PduR_PduType"]
end
subgraph Dests["Destinations Array (DestPduRef[0..N])"]
D0["[0] to: Dcm"]
D1["[1] to: Mirror"]
D2["[2] to: CanTp"]
end
subgraph API["API Tables (PduR_ApiType)"]
ADCM["DcmApi: StartOfReception / CopyRxData / TpRxIndication / CopyTxData / TpTxConfirmation"]
AMIR["MirrorApi: TxConfirmation"]
ACTP["CanTpApi: GwStartOfReception / GwCopyRxData / GwRxIndication / GwCopyTxData / GwTxConfirmation / CanTp_Transmit"]
end
subgraph GW["Gateway Buffer (optional)"]
GB["GwBuffer / DestTxBufferRef<br/>static uint8[] or MemPool"]
end
SP --> D0
SP --> D1
SP --> D2
D0 -.-> ADCM
D1 -.-> AMIR
D2 -.-> ACTP
D2 -.-> GW
Routing Patterns:
| API | Fan-out | Target | Gateway Support |
|—–|———|——–|—————-|
| PduR_Transmit / PduR_RxIndication | All destinations | DestPduRef[0..N] | No |
| PduR_TpTransmit | First only | DestPduRef[0] | Yes (uses GwBuffer) |
| PduR_StartOfReception / CopyRxData / TpRxIndication | First only | DestPduRef[0] | No |
| PduR_CopyTxData / TxConfirmation | Source only | SrcPduRef | Yes (uses GwBuffer) |
| PduR_Gw* | Gateway-specific | Buffer -> DestPduRef[0..N] | Yes |
{
"name": "DiagRequest_RX",
"from": "CanTp",
"to": "Dcm"
}
Routes PDUs from CanTp (transport layer) to Dcm (diagnostic manager).
{
"name": "CAN0_Diag",
"from": "CanTp",
"to": "DoIP",
"DestBufferSize": 2048
}
Routes PDUs from CanTp to DoIP with a dedicated 2048-byte gateway buffer.
{
"name": "CAN1_MSG",
"from": "CanIf",
"to": "Com",
"destinations": [
{
"name": "CAN1_MSG_MIRROR",
"to": "Mirror",
"from": "CanIf"
}
]
}
Routes CAN message to Com and also mirrors it to the Mirror module for monitoring.
{
"name": "J1939_To_CanTp",
"from": "J1939Tp",
"to": "CanTp",
"DestBuffer": "GwBuf"
}
Routes PDUs from J1939Tp to CanTp using a shared buffer named GwBuf (defined in buffers[]).
For each routine, the following macros are generated in PduR_Cfg.h:
#define PDUR_<name> <index>
#define PDUR_<dest> <index> // only if dest != name
#define PDUR_<fake> <index> // only if fake is set
#define PDUR_<destinations[i].name> <index> // for each destination
#define PDUR_<destinations[i].fake> <index> // for each destination with fake
Networks define logical communication channels (e.g., CAN0, LIN0) that are used to auto-generate routines from DBC files. Unlike CanIf (which handles physical bus configuration), PduR networks focus on inter-module routing discovery.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | CAN? |
Logical name of the network (e.g., CAN0). Used as prefix for generated PDU symbols. |
network |
string | Yes | - | Physical network type. Must be "CAN" or "LIN". Determines the lower module: CAN -> CanIf, LIN -> LinIf. |
me |
string | Yes | AS |
Self node name. Messages where node == me are treated as transmit (Com -> CanIf/LinIf); others are receive (CanIf/LinIf -> Com). |
use_dbc |
boolean | No | false |
Enable DBC-based routine generation. When true, dbc must point to a valid file. |
dbc |
string | Conditional | "" |
Path to a Vector CAN DBC file. Resolved relative to the configuration directory. Required when use_dbc is true. |
ignore |
array | No | - | List of PDU/message names to exclude from DBC-based routine generation. |
When use_dbc is true, the extract() function in the generator:
ignore:
msg.node == me (self-transmitted): generates a TX routine (from: "Com" -> to: "CanIf"/"LinIf"), PDU name suffixed with _TX.msg.node != me (received from others): generates an RX routine (from: "CanIf"/"LinIf" -> to: "Com"), PDU name suffixed with _RX.PduR.json in the output directory.Common suffixes:
_RXfor receive,_TXfor transmit. The generator checks for these suffixes and appends them if missing.
{
"name": "CAN0",
"network": "CAN",
"me": "AS",
"use_dbc": true,
"dbc": "config/CAN0.dbc",
"ignore": ["DEBUG_MSG", "TEST_MSG"]
}
This generates routing routines for all messages in CAN0.dbc except DEBUG_MSG and TEST_MSG.
The memory array defines memory pools used for PduR internal data buffering. When configured, the PDUR_USE_MEMPOOL macro is generated, and MemCluster definitions are emitted.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | - | Memory pool name. Used as cluster identifier. |
size |
integer | No | 256 | Size of each memory block in bytes. Range: 0 - 4294967295. |
number |
integer | No | 2 | Number of memory blocks in the pool. Range: 0 - 4294967295. |
"memory": [
{
"name": "PduR_MemPool",
"size": 512,
"number": 4
}
]
Creates a memory pool named PduR_MemPool with 4 blocks of 512 bytes each.
When memory is present, the generator:
#define PDUR_USE_MEMPOOL in the header.MemCluster macros via MC.Gen_Macros().MC.Gen_Defs().&MC_PduR in PduR_Config.The buffers array defines shared gateway buffer pools that can be referenced by multiple routines via the DestBuffer parameter. These are used in TP-to-TP gateway scenarios for temporary data storage during routing.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | - | Buffer name. Referenced by routine DestBuffer. |
size |
integer | No | 4096 | Buffer size in bytes. Range: 0 - 4294967295. |
"buffers": [
{
"name": "GwBuf",
"size": 8192
}
]
Allocates a uint8_t PduR_GwBuffer_GwBuf[8192] static buffer.
For each buffer entry, the generator emits:
static uint8_t PduR_GwBuffer_<name>[<size>];
The following build-time configuration flags are controlled via macros:
| Macro | Description | Default |
|---|---|---|
PDUR_USE_PB_CONFIG |
Enable post-build configuration support | Enabled |
PDUR_USE_MEMPOOL |
Enable memory pool support | When memory is configured |
PDUR_USE_TP_GATEWAY |
Enable TP-to-TP gateway support | When any routine has TP-to-TP routing |
The PDUR_USE_PB_CONFIG macro is controlled by the UsePostBuildConfig setting (defaults to true) at the PduR configuration level. If set to false, the macro is commented out.
The PduR public API is defined in PduR.h following AUTOSAR CP 4.4.0.
| Macro | Value | Description |
|---|---|---|
PDUR_E_PDU_ID_INVALID |
0x02 | PDU ID is out of valid range |
PDUR_E_ROUTING_PATH_GROUP_ID_INVALID |
0x08 | Routing path group ID is invalid |
PDUR_E_PARAM_POINTER |
0x09 | Null pointer passed to API |
| Function | Description |
|---|---|
PduR_Init(const PduR_ConfigType *ConfigPtr) |
Initializes the PduR module. When PDUR_USE_MEMPOOL is defined, calls PduR_MemInit() to initialize memory pools. |
PduR_EnableRouting(PduR_RoutingPathGroupIdType id) |
Enables a routing path group. |
PduR_DisableRouting(PduR_RoutingPathGroupIdType id, boolean initialize) |
Disables a routing path group. |
PduR_GetVersionInfo(Std_VersionInfoType *versionInfo) |
Returns PduR module version information. Reports: vendor STD_VENDOR_ID_AS, module MODULE_ID_PDUR, version 4.0.0. |
Each connected module exposes a set of adapter functions that PduR uses as callback entry points. These are defined in module-specific headers:
| Function | Direction | Description |
|---|---|---|
PduR_CanIfRxIndication(RxPduId, PduInfoPtr) |
Rx | Forwards CAN receive indication to PduR routing. Delegates to PduR_RxIndication(). |
PduR_CanIfTxConfirmation(TxPduId, result) |
Tx | Forwards CAN transmit confirmation. Delegates to PduR_TxConfirmation(). |
| Function | Description |
|---|---|
PduR_CanTpStartOfReception(id, info, TpSduLength, bufferSizePtr) |
Delegates to PduR_StartOfReception() |
PduR_CanTpCopyRxData(id, info, bufferSizePtr) |
Delegates to PduR_CopyRxData() |
PduR_CanTpCopyTxData(id, info, retry, availableDataPtr) |
Delegates to PduR_CopyTxData() |
PduR_CanTpRxIndication(id, result) |
Delegates to PduR_TpRxIndication() |
PduR_CanTpTxConfirmation(id, result) |
Delegates to PduR_TxConfirmation() |
PduR_CanTpGwStartOfReception(id, info, TpSduLength, bufferSizePtr) |
Gateway: delegates to PduR_GwStartOfReception() |
PduR_CanTpGwCopyRxData(id, info, bufferSizePtr) |
Gateway: delegates to PduR_GwCopyRxData() |
PduR_CanTpGwCopyTxData(id, info, retry, availableDataPtr) |
Gateway: delegates to PduR_GwCopyTxData() |
PduR_CanTpGwRxIndication(id, result) |
Gateway: invokes LINTP_GW_USER_HOOK_RX_IND then delegates to PduR_GwRxIndication() |
PduR_CanTpGwTxConfirmation(id, result) |
Gateway: delegates to PduR_GwTxConfirmation() |
| Function | Description |
|---|---|
PduR_ComTransmit(TxPduId, PduInfoPtr) |
Delegates to PduR_Transmit() |
PduR_ComRxIndication(RxPduId, PduInfoPtr) |
Delegates to PduR_RxIndication() |
PduR_ComTxConfirmation(TxPduId, result) |
Delegates to PduR_TxConfirmation() |
PduR_ComTriggerTransmit(TxPduId, PduInfoPtr) |
Trigger transmit (SWS_PduR_00369) |
| Function | Description |
|---|---|
PduR_DcmTransmit(TxPduId, PduInfoPtr) |
Delegates to PduR_TpTransmit() |
PduR_DcmCancelTransmit(TxPduId) |
Cancel ongoing TP transmit |
PduR_DcmCancelReceive(RxPduId) |
Cancel ongoing TP receive |
| Function | Description |
|---|---|
PduR_DoIPStartOfReception(id, info, TpSduLength, bufferSizePtr) |
Delegates to PduR_StartOfReception() |
PduR_DoIPCopyRxData(id, info, bufferSizePtr) |
Delegates to PduR_CopyRxData() |
PduR_DoIPCopyTxData(id, info, retry, availableDataPtr) |
Delegates to PduR_CopyTxData() |
PduR_DoIPRxIndication(id, result) |
Delegates to PduR_TpRxIndication() |
PduR_DoIPTxConfirmation(id, result) |
Delegates to PduR_TxConfirmation() |
PduR_DoIPGwStartOfReception(id, info, TpSduLength, bufferSizePtr) |
Gateway: delegates to PduR_GwStartOfReception() |
PduR_DoIPGwCopyRxData(id, info, bufferSizePtr) |
Gateway: delegates to PduR_GwCopyRxData() |
PduR_DoIPGwCopyTxData(id, info, retry, availableDataPtr) |
Gateway: delegates to PduR_GwCopyTxData() |
PduR_DoIPGwRxIndication(id, result) |
Gateway: delegates to PduR_GwRxIndication() |
PduR_DoIPGwTxConfirmation(id, result) |
Gateway: delegates to PduR_GwTxConfirmation() |
| Function | Description |
|---|---|
PduR_J1939TpTransmit(TxPduId, PduInfoPtr) |
Delegates to PduR_TpTransmit() |
PduR_J1939TpStartOfReception(id, info, TpSduLength, bufferSizePtr) |
Delegates to PduR_StartOfReception() |
PduR_J1939TpCopyRxData(id, info, bufferSizePtr) |
Delegates to PduR_CopyRxData() |
PduR_J1939TpCopyTxData(id, info, retry, availableDataPtr) |
Delegates to PduR_CopyTxData() |
PduR_J1939TpRxIndication(id, result) |
Delegates to PduR_TpRxIndication() |
PduR_J1939TpTxConfirmation(id, result) |
Delegates to PduR_TxConfirmation() |
Same function set as CanTp (StartOfReception, CopyRxData, CopyTxData, RxIndication, TxConfirmation + Gateway variants).
| Function | Description |
|---|---|
PduR_SecOCTransmit(TxPduId, PduInfoPtr) |
Delegates to PduR_Transmit() |
PduR_SecOCRxIndication(RxPduId, PduInfoPtr) |
Delegates to PduR_RxIndication() |
PduR_SecOCTxConfirmation(TxPduId, result) |
Delegates to PduR_TxConfirmation() |
PduR_SecOCTriggerTransmit(TxPduId, PduInfoPtr) |
Trigger transmit |
| Function | Description |
|---|---|
PduR_MirrorTransmit(TxPduId, PduInfoPtr) |
Delegates to PduR_TpTransmit() |
The private header PduR_Priv.h defines the core runtime data structures.
PduR_ModuleType)typedef enum {
PDUR_MODULE_CANIF, // 0 - CAN Interface
PDUR_MODULE_CANTP, // 1 - CAN Transport Protocol
PDUR_MODULE_J1939TP, // 2 - J1939 Transport Protocol
PDUR_MODULE_LINIF, // 3 - LIN Interface
PDUR_MODULE_LINTP, // 4 - LIN Transport Protocol
PDUR_MODULE_DOIP, // 5 - DoIP Transport Protocol
PDUR_MODULE_CANNM, // 6 - CAN Network Management
PDUR_MODULE_OSEKNM, // 7 - OSEK Network Management
/* ---- boundary ---- */
PDUR_MODULE_ISOTP, // 8 - ISO-TP boundary marker
PDUR_MODULE_SECOC, // 9 - Secure On-Board Communication
PDUR_MODULE_COM, // 10 - Communication (signal-based)
PDUR_MODULE_DCM, // 11 - Diagnostic Communication Manager
PDUR_MODULE_MIRROR, // 12 - Mirror module
} PduR_ModuleType;
Architectural Significance: Modules at or below
PDUR_MODULE_ISOTP(0-8) are treated as “lower-layer” modules. Modules abovePDUR_MODULE_ISOTP(9-12) are “upper-layer” modules. This affects gateway routing behavior (see Gateway Data Flow).
PduR_ApiType)Each module registers a table of 7 function pointers:
typedef struct {
BufReq_ReturnType (*StartOfReception)(PduIdType, const PduInfoType*,
PduLengthType, PduLengthType*);
BufReq_ReturnType (*CopyRxData)(PduIdType, const PduInfoType*, PduLengthType*);
void (*TpRxIndication)(PduIdType, Std_ReturnType);
void (*RxIndication)(PduIdType, const PduInfoType*);
Std_ReturnType (*Transmit)(PduIdType, const PduInfoType*);
BufReq_ReturnType (*CopyTxData)(PduIdType, const PduInfoType*,
const RetryInfoType*, PduLengthType*);
void (*TxConfirmation)(PduIdType, Std_ReturnType);
} PduR_ApiType;
NULL pointers are allowed for unused callbacks. Each module fills in only the callbacks it supports.
PduR_PduType)typedef struct {
PduR_ModuleType Module; // Module identifier (enum)
PduIdType PduHandleId; // PDU identifier for the module
const PduR_ApiType *api; // Pointer to module's API table
} PduR_PduType;
PduR_BufferType)typedef struct {
uint8_t *data; // Pointer to buffer data
PduLengthType size; // Total buffer size
PduLengthType index; // Current read/write position
} PduR_BufferType;
PduR_RoutingPathType)typedef struct {
const PduR_PduType *SrcPduRef; // Source PDU descriptor
const PduR_PduType *DestPduRef; // Destination PDU array (first entry)
PduR_BufferType *DestTxBufferRef; // Gateway transmit buffer (optional)
uint8_t *GwBuffer; // Static gateway destination buffer
PduLengthType GwBufferSize; // Static buffer size
uint16_t numOfDestPdus; // Number of destination entries
} PduR_RoutingPathType;
struct PduR_Config_s {
#if defined(PDUR_USE_MEMPOOL)
const mem_cluster_t *mc; // Memory pool cluster descriptor
#endif
const PduR_RoutingPathType *RoutingPaths; // Array of all routing paths
uint16_t numOfRoutingPaths; // Number of routing paths
};
Each PduR API function follows a specific routing pattern based on the path configuration.
PduR_Transmit)pathId against numOfRoutingPaths (reports PDUR_E_PDU_ID_INVALID on failure).PduInfoPtr and PduInfoPtr->SduDataPtr (reports PDUR_E_PARAM_POINTER on failure).DestPduRef[0..numOfDestPdus-1]).Transmit callback.E_OK only if all transmits succeed; otherwise returns the first failure code.PduR_TpTransmit)DestPduRef[0] (the first destination only, not all).DestTxBufferRef != NULL), uses pathId as the PDU handle.PduHandleId.PduR_StartOfReception -> PduR_CopyRxData -> PduR_TpRxIndication)All three functions route to DestPduRef[0] only:
PduR_RxIndication)PduR_Transmit).RxIndication callback.PduR_CopyTxData, PduR_TxConfirmation)SrcPduRef (the source module, not the destination).pathId as the PDU handle.PduHandleId.A consistent pattern is used throughout: when DestTxBufferRef is not NULL (gateway mode), the pathId itself serves as the PDU handle ID. Otherwise, the module’s configured PduHandleId is used:
if (RoutingPath->DestTxBufferRef != NULL)
PduHandleId = pathId; // Use routing path index
else
PduHandleId = DestPduRef->PduHandleId; // Use module's PDU ID
Gateway routing handles TP-to-TP forwarding (e.g., CanTp <-> DoIP, CanTp <-> LinTp). The gateway mechanism uses an internal buffer to temporarily store the complete TP message before forwarding.
The following sequence diagram shows the complete lifecycle of a gateway TP-to-TP forwarding:
sequenceDiagram
participant SRC as Source TP Module (e.g. CanTp)
participant PR as PduR Gateway
participant BUF as Gateway Buffer (GwBuffer / MemPool)
participant DST_H as Upper Dest (e.g. Dcm, >ISOTP)
participant DST_L as Lower Dest (e.g. CanIf, <=ISOTP)
Note over SRC,PR: Incoming TP frame arrives
SRC->>PR: GwStartOfReception(id, info, length, &bufSize)
PR->>BUF: Allocate buffer (static or mempool)
BUF-->>PR: buffer allocated
PR-->>SRC: BUFREQ_OK
loop For each data segment
SRC->>PR: GwCopyRxData(id, info, &bufSize)
PR->>BUF: Copy data segment to buffer[index]
BUF-->>PR: data copied
PR-->>SRC: BUFREQ_OK
end
SRC->>PR: GwRxIndication(id, E_OK)
PR->>BUF: Rewind buffer index
par Forward to upper-layer destinations (>ISOTP)
PR->>DST_H: StartOfReception(id, info, length, &bufSize)
DST_H-->>PR: BUFREQ_OK
PR->>DST_H: CopyRxData(id, info, &bufSize)
DST_H-->>PR: BUFREQ_OK
PR->>DST_H: TpRxIndication(id, E_OK)
and Forward to lower-layer destinations (<=ISOTP)
PR->>DST_L: Transmit(id, &PduInfo)
DST_L-->>PR: E_OK/E_NOT_OK
end
Note over SRC,PR: Final cleanup
SRC->>PR: GwTxConfirmation(id, E_OK)
PR->>BUF: Free buffer (mempool) or reset (static)
PduR_GwStartOfReception - Buffer AllocationGwBuffer != NULL and GwBufferSize >= TpSduLength):
buffer->data = RoutingPath->GwBufferPDUR_USE_MEMPOOL):
PduR_MemAlloc(TpSduLength) to allocate exact size needed.buffer->size = TpSduLength, buffer->index = 0, returns BUFREQ_OK.PduR_GwCopyRxData - Data Copyinginfo->SduDataPtr into buffer->data[buffer->index].buffer->index by info->SduLength.BUFREQ_E_OVFL if buffer overflow is detected.PduR_GwRxIndication - Forwarding LogicOn successful reception (result == E_OK), iterates through all destinations:
| Destination Module Type | Behavior |
|---|---|
Upper-layer (Module > PDUR_MODULE_ISOTP, e.g., SecOC, Com, Dcm, Mirror) |
Calls StartOfReception + CopyRxData + TpRxIndication sequence to deliver the complete buffered data as a TP reception. |
Lower-layer (Module <= PDUR_MODULE_ISOTP, e.g., CanIf, CanTp, DoIP) |
Sets buffer->index = 0 and calls Transmit directly with the complete buffered data as a single I-PDU. |
On failure (E_NOT_OK), if PDUR_USE_MEMPOOL and the buffer was dynamically allocated, the buffer is freed via PduR_MemFree().
PduR_GwCopyTxData() -- Copy from buffer to output (for retry)
|
v
PduR_GwTxConfirmation() -- Free buffer after successful transmit
PduR_GwCopyTxData - Outbound Data Copyoffset from info->MetaDataPtr.info->SduLength bytes from buffer->data[offset] to info->SduDataPtr.BUFREQ_OK.PduR_GwTxConfirmation - Buffer Cleanupbuffer->data = NULL.PDUR_USE_MEMPOOL and the buffer was dynamically allocated (not the static GwBuffer), calls PduR_MemFree().The PduR implementation supports zero-cost routing macros that bypass the PduR layer entirely for direct module-to-module connections, eliminating routing overhead at compile time.
| Macro | Effect |
|---|---|
PDUR_DCM_CANTP_ZERO_COST |
PduR_DcmTransmit -> CanTp_Transmit (direct), PduR_CanTp* callbacks -> Dcm_* (direct) |
PDUR_DCM_LINTP_ZERO_COST |
PduR_DcmTransmit -> LinTp_Transmit (direct), PduR_LinTp* callbacks -> Dcm_* (direct) |
PDUR_DCM_J1939TP_ZERO_COST |
PduR_J1939Tp* callbacks -> Dcm_* (direct) |
When enabled, the corresponding adapter functions are replaced by #define macros in the header files, eliminating function call overhead and reducing code size.
Example from PduR_Dcm.h:
#ifdef PDUR_DCM_CANTP_ZERO_COST
#define PduR_DcmTransmit CanTp_Transmit
#endif
Example from PduR_CanTp.h:
#ifdef PDUR_DCM_CANTP_ZERO_COST
#define PduR_CanTpCopyTxData Dcm_CopyTxData
#define PduR_CanTpRxIndication Dcm_TpRxIndication
#define PduR_CanTpTxConfirmation Dcm_TpTxConfirmation
#define PduR_CanTpStartOfReception Dcm_StartOfReception
#define PduR_CanTpCopyRxData Dcm_CopyRxData
#endif
The LinTp gateway implementation provides user-defined hook macros for custom behavior:
| Hook Macro | Location | Description |
|---|---|---|
LINTP_GW_USER_HOOK_RX_IND(id, result) |
PduR_LinTp.c | Called before PduR_GwRxIndication(). Default: no-op. |
LINTP_GW_USER_HOOK_TX_CONFIRM(id, result) |
PduR_LinTp.c | Called before PduR_TxConfirmation(). Default: no-op. |
These hooks allow application-specific processing (e.g., logging, metrics, traffic shaping) without modifying the PduR core code.
PduR integrates with the Default Error Tracer (Det) module for runtime diagnostic error reporting. All API functions validate parameters using the DET_VALIDATE macro:
| Validation | Error Code | Reported Service ID |
|---|---|---|
pathId >= numOfRoutingPaths |
PDUR_E_PDU_ID_INVALID |
Function-specific (0x40-0xF5) |
| NULL pointer in Transmit | PDUR_E_PARAM_POINTER |
0x49 |
| NULL pointer in GetVersionInfo | PDUR_E_PARAM_POINTER |
0xF1 |
The DET_THIS_MODULE_ID is set to MODULE_ID_PDUR.
The memory pool subsystem (PduR_Mem.c) provides dynamic buffer allocation for gateway scenarios. It is compiled only when PDUR_USE_MEMPOOL is defined.
| Function | Description |
|---|---|
PduR_MemInit() |
Initializes the memory pool cluster via mc_init(config->mc) |
PduR_MemAlloc(size) |
Allocates a buffer of size bytes from the pool |
PduR_MemGet(size) |
Gets next available buffer without allocation |
PduR_MemFree(buffer) |
Returns a buffer to the pool |
The memory pool is configured via the memory[] configuration array (see Section 6) and is managed by the MemPool library (linked via SConscript).
From app/bootloader/config/PduR/PduR.json:
{
"class": "PduR",
"routines": [
{ "name": "P2P_RX", "from": "CanTp", "to": "Dcm" },
{ "name": "P2P_TX", "from": "Dcm", "to": "CanTp" },
{ "name": "P2A_RX", "from": "CanTp", "to": "Dcm" },
{ "name": "P2A_TX", "from": "Dcm", "to": "CanTp" }
]
}
Simple diagnostic request/response routing without gateway or DBC support.
From app/app/config/Com/PduR.json:
{
"class": "PduR",
"routines": [
{ "name": "P2P_RX", "from": "CanTp", "to": "Dcm" },
{ "name": "P2P_TX", "from": "Dcm", "to": "CanTp" },
{ "name": "P2A_RX", "from": "CanTp", "to": "Dcm",
"destinations": [{ "name": "P2A_FW_TX", "to": "CanTp", "fake": "P2A_FW_RX" }] },
{ "name": "P2A_TX", "from": "Dcm", "to": "CanTp" },
{ "name": "CAN0_SECOC_MSG0_TX", "from": "Com", "to": "SecOC" },
{ "name": "FW_CAN0_SECOC_MSG0_TX", "from": "SecOC", "to": "CanIf" },
{ "name": "FW_CAN0_SECOC_MSG1_RX", "from": "CanIf", "to": "SecOC" },
{ "name": "CAN0_SECOC_MSG1_RX", "from": "SecOC", "to": "Com" },
{ "name": "MIRROR_TX", "from": "Mirror", "to": "CanIf" }
],
"networks": [
{ "name": "CAN0", "network": "CAN", "me": "AS", "dbc": "CAN0.dbc",
"ignore": ["CanNmUserData"] },
{ "name": "CAN1", "network": "CAN", "me": "AS", "dbc": "CAN0.dbc",
"ignore": ["CanNmUserData"] }
],
"memory": [
{ "name": "middle", "size": 64, "number": 2 }
]
}
Key features demonstrated:
Com -> SecOC -> CanIf for TX, CanIf -> SecOC -> Com for RXP2A_FW_TX with fake for mirrored receive)Mirror -> CanIf allows test/monitoring injectionAlternative routing paths (commented as backup-routines-secoc-test-over-cantp) demonstrate routing SecOC-protected PDUs through CanTp instead of CanIf:
{
"name": "FW_CAN0_SECOC_MSG0_TX",
"from": "SecOC",
"to": "CanTp"
},
{
"name": "FW_CAN0_SECOC_MSG0_RX",
"from": "CanTp",
"to": "SecOC",
"dest": "CAN0_SECOC_MSG1_RX"
}
The SConscript build script:
.c files in the PduR directory.CanIf_Cfg, Com_Cfg, CanTp_Cfg, LinTp_Cfg, J1939Tp_Cfg, Dcm_Cfg, NvM_Cfg, SecOC_Cfg, Mirror_Cfg, DoIP_Cfg.MemPool library when the compiler is not CWS12 (CodeWarrior for HC(S)12).The generator produces two files in <cfg_dir>/GEN/:
| File | Description |
|---|---|
PduR_Cfg.h |
Header with PDUR_<name> macros, configuration flags, and MemCluster macros. |
PduR_Cfg.c |
Source with routing tables, API tables, buffer definitions, and PduR_Config structure. |
For each module referenced in any routine, a PduR_<Module>Api table is generated containing function pointers for:
PduR_ApiType {
StartOfReception // called when a TP reception starts
CopyRxData // copy received data
TpRxIndication // TP reception complete indication
RxIndication // single-frame reception indication (Com only)
Transmit // transmit function
CopyTxData // copy data for transmission
TxConfirmation // transmit confirmation
}
Gateway modules (when hasGW is true) get gateway-specific callbacks:
PduR_<Mod>GwStartOfReceptionPduR_<Mod>GwCopyRxDataPduR_<Mod>GwRxIndicationPduR_<Mod>GwCopyTxDataPduR_<Mod>GwTxConfirmationconst PduR_ConfigType PduR_Config = {
&MC_PduR, // MemCluster pointer (if PDUR_USE_MEMPOOL)
PduR_RoutingPaths, // routing path table
ARRAY_SIZE(PduR_RoutingPaths) // number of routing paths
};
PduR.pyThe Generator PduR.py script:
extract() to process DBC files and auto-generate routines.Gen_PduR() to produce PduR_Cfg.h and PduR_Cfg.c in the GEN/ output directory.extract())routines, memory, and buffers from configuration.dbc file:
../).Com.get_messages().node == me comparison.PduR.json.Gen_PduR())PduR_RoutingPaths[] table.PduR_Config structure.| Section | Type | Required | Description |
|---|---|---|---|
routines |
array | Yes | PDU routing rules (at least one required). |
networks |
array | No | Network definitions for DBC-based auto-generation. |
memory |
array | No | Memory pool configuration. |
buffers |
array | No | Shared gateway buffer pools. |
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | - | PDU name (referenced from EcuC.Pdus). |
from |
enum | - | Source module. |
to |
enum | - | Destination module. |
useDest |
bool | true |
Enable/disable alternative destination name. |
dest |
string | name |
Alternative destination PDU name. |
useDestBuffer |
bool | false |
Enable/disable gateway buffer. |
DestBufferType |
string | private |
"private" or "shared". |
DestBuffer |
string | - | Shared gateway buffer name. |
DestBufferSize |
int | 0 | Private gateway buffer size. |
useFake |
bool | true |
Enable/disable fake PDU name for mirroring. |
fake |
string | - | Fake PDU name for mirroring. |
destinations |
array | - | Additional routing legs. |
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | CAN? |
Logical network name. |
network |
enum | - | "CAN" or "LIN". |
me |
string | AS |
Self node name. |
use_dbc |
bool | false |
Enable DBC parsing. |
dbc |
string | "" |
Path to DBC file. |
ignore |
array | - | PDUs to exclude from DBC parsing. |
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | - | Memory pool name. |
size |
int | 256 | Block size in bytes. |
number |
int | 2 | Number of blocks. |
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | - | Buffer name. |
size |
int | 4096 | Buffer size in bytes. |