UDSLib separates core diagnostic logic from the input/output layer and the operating system.
Three rules define the library's structure:
- Strict Isolation: Logic runs independently of I/O and OS specifics.
- No Resource Ownership: The library does not allocate memory or create threads.
- Dependency Injection: Platform-specific functions are injected at runtime via function pointers.
The library divides into four main areas:
- Service Registry: A table-driven dispatcher that routes requests.
- Core SDU Engine: Parses and validates protocol requirements (Session, Security, Length).
- State Manager: Tracks sessions, security levels, and timers (S3, P2). It uses optional hooks for NVM persistence.
- Transport Abstraction: A layer that connects to OS sockets (Zephyr/Linux) or uses the internal ISO-TP fallback.
graph TD
App[User Application] -->|uds_client_request| Core
App -->|uds_init/process| Core
Core -->|Lookup| Registry[Service Registry]
Registry -->|Handler| Ext[External/User Service]
Registry -->|Handler| Builtin[Built-in Service]
Core -->|Condition Check| Gate{Safety Gate}
Gate -->|Passed| Registry
Gate -->|Rejected| NRC[Send NRC 0x22]
Core[UDSLib Core] -->|SDU Send| TP[Transport Layer]
TP -->|CAN Frame| HW[Hardware/HAL]
HW -->|CAN Frame| TP
TP -->|SDU Input| Core
Core -->|Callback| App
A table-driven dispatcher manages UDS services.
- Scalability: Adding a service (like SID 0x29) requires adding an entry to the service table.
- Extensibility: Applications register
user_servicesinuds_config_tto override or extend standard functionality. - Validation: The core engine enforces ISO 14229-1 NRC priorities (Session → Subfunction → Length → Security → Safety) before calling the handler.
For industrial and automotive safety, UDSLib implements Safety Gates.
Every potentially destructive service (Reset, Write, Download) passes through an application-provided fn_is_safe callback.
- If the callback returns
false, the stack rejects the request with NRC 0x22 (ConditionsNotCorrect). - This allows engineers to block diagnostics when the machine is in an unsafe state.
The protocol state (Active Session and Security Level) persists across power cycles using NVM Persistence Hooks.
fn_nvm_save: Runs when the session or security level changes.fn_nvm_load: Runs duringuds_initto restore the last known valid state.
The Transport Layer (ISO 15765-2) operates as a pluggable module.
- SDU (Service Data Unit): A complete UDS message (e.g.,
[0x10, 0x03]). - PDU (Protocol Data Unit): A single CAN frame (e.g.,
[0x02, 0x10, 0x03, 0x00...]).
The udslib core logic strictly consumes and produces SDUs.
If the underlying OS (like Zephyr or Linux) has a native ISO-TP stack, UDSLib communicates directly at the SDU level. This removes redundant reassembly logic.
If the OS is "dumb" (Bare Metal), UDSLib uses the uds_tp_isotp.c fallback to handle reassembly, converting SDUs into raw CAN PDUs.
To ensure MISRA-C compliance and reliability:
- The library never calls
malloc()orfree(). - The caller provides buffers for RX and TX operations.
- Message structures use fixed sizes.
The uds_process() function runs the stack. It is designed for a loop and does not block. It uses the get_time_ms() callback to check if internal timers (S3, P2, P2*) have expired.
This allows udslib to fit into different scheduling models:
- Super Loop: Call once per loop.
- RTOS Task: Call periodically with
vTaskDelayork_sleep. - Interrupt Mode: Call when a hardware timer triggers.