can_uds is a lightweight, portable implementation of the ISO14229-1 (Unified Diagnostic Services) protocol stack. It is designed specifically for embedded systems and features a robust port for the RT-Thread real-time operating system.
It enables your device to act as a UDS Server (ECU) over the CAN bus (via ISO-TP), leveraging RT-Thread's device framework and IPC mechanisms for efficient, non-blocking operation.
- Separation of Concerns: The core UDS logic (
iso14229.c) is strictly decoupled from the OS/Hardware layer (iso14229_rtt.c). - RT-Thread Integration: Native support for RT-Thread threads, message queues, and CAN device drivers.
- Efficient Dispatching: Utilizes an O(1) lookup table and a "Chain of Responsibility" pattern for event handling, allowing multiple callbacks for a single Service ID (SID).
- User-Controlled I/O: The library does not monopolize the CAN interrupt. Users feed data into the stack via a simple API (
rtt_uds_feed_can_frame), allowing for flexible filtering and sharing of the CAN bus. - Static Memory Friendly: Service nodes are allocated by the user (typically statically), minimizing dynamic memory fragmentation.
| Name | Description |
|---|---|
| examples | Example code for RT-Thread (MSH commands) |
| iso14229.c/h | Core UDS protocol logic |
| iso14229_rtt.c/h | RT-Thread porting layer |
| rtt_uds_config.h | Default configuration file |
| Kconfig | RT-Thread menuconfig description |
| SConscript | RT-Thread build script |
| LICENSE | License file |
can_uds is licensed under the MIT License. See the LICENSE file for details.
Enable the package using RT-Thread's menuconfig:
RT-Thread online packages --->
peripherals packages --->
[*] Enable iso14229 (UDS) library --->
(32) Event Dispatch Table Size
[*] Enable UDS server example application
Step 1: Define a Service Handler
Create a callback function for the specific UDS service (e.g., 0x2E WriteDataByIdentifier) and define the node using the helper macro.
#include "iso14229_rtt.h"
static UDSErr_t handle_led_control(UDSServer_t *srv, void *data) {
UDSWDBIArgs_t *args = (UDSWDBIArgs_t *)data;
if (args->dataId == 0x0100) {
// Perform business logic...
return UDS_PositiveResponse;
}
return UDS_NRC_RequestOutOfRange; // Pass to next handler
}
/* Define the node statically */
RTT_UDS_SERVICE_DEFINE(led_node, UDS_EVT_WriteDataByIdent, handle_led_control);Step 2: Initialize & Register
Create the UDS instance and register your service node.
rtt_uds_config_t cfg = {
.can_name = "can1",
.phys_id = 0x7E0,
.func_id = 0x7DF,
.resp_id = 0x7E8,
.func_resp_id = UDS_TP_NOOP_ADDR,
.thread_name = "uds_task",
.stack_size = 2048,
.priority = 12,
.rx_mq_pool_size = 32
};
rtt_uds_env_t *env = rtt_uds_create(&cfg);
rtt_uds_service_register(env, &led_node);Step 3: Feed CAN Data
In your CAN RX callback, read the data and feed it to the stack.
static rt_err_t can_rx_callback(rt_device_t dev, rt_size_t size) {
struct rt_can_msg msg;
if (rt_device_read(dev, 0, &msg, sizeof(msg)) == sizeof(msg)) {
rtt_uds_feed_can_frame(env, &msg); // Non-blocking
}
return RT_EOK;
}The examples directory contains a ready-to-run example (app_uds_example.c). It provides MSH commands to start/stop the UDS server.
Usage in MSH:
msh > uds_example start can1
UDS Started on can1.Testing with Linux cansend:
# Send WriteDataByIdentifier (0x2E) to DID 0x0001 with value 0x01
cansend can0 7E0#042E000101- Author: wdfk-prog
- Repository: https://github.com/wdfk-prog/can_uds
- Email: [email protected]
If you find this package helpful, please give it a Star!
can_uds 是一个轻量级、可移植的 ISO14229-1 (统一诊断服务) 协议栈实现。它是专为嵌入式系统设计的,并包含针对 RT-Thread 实时操作系统的全功能移植层。
它支持基于 CAN 总线(通过 ISO-TP)的 UDS 服务器(ECU)角色,利用 RT-Thread 的设备框架和 IPC 机制实现高效、非阻塞的运行。
- 关注点分离:核心逻辑 (
iso14229.c) 与 OS/硬件层 (iso14229_rtt.c) 严格解耦。 - RT-Thread 集成:内置对 RT-Thread 线程、消息队列和 CAN 设备驱动的支持。
- 高效分发:使用 O(1) 查找表和“责任链”模式处理服务回调,支持同一服务 ID (SID) 注册多个处理函数(例如不同模块处理不同的 DID)。
- 用户控制 I/O:库不独占 CAN 中断。用户通过简单的 API (
rtt_uds_feed_can_frame) 将数据投递到协议栈,允许用户灵活过滤或共享 CAN 总线。 - 静态内存友好:服务节点由用户分配(通常是静态定义的),减少动态内存碎片。
| 名称 | 描述 |
|---|---|
| examples | RT-Thread 示例代码 (MSH 命令) |
| iso14229.c/h | UDS 协议核心逻辑 |
| iso14229_rtt.c/h | RT-Thread 移植层 |
| rtt_uds_config.h | 默认配置文件 |
| Kconfig | RT-Thread menuconfig 配置描述 |
| SConscript | RT-Thread 构建脚本 |
| LICENSE | 许可证文件 |
can_uds 遵循 MIT 许可证。详情请参阅 LICENSE 文件。
在 RT-Thread 的 menuconfig 中启用该软件包:
RT-Thread online packages --->
peripherals packages --->
[*] Enable iso14229 (UDS) library --->
(32) Event Dispatch Table Size (事件分发表大小)
[*] Enable UDS server example application (启用示例)
步骤 1: 定义服务处理函数
为特定的 UDS 服务(如 0x2E 写数据)创建回调函数,并使用宏定义节点。
#include "iso14229_rtt.h"
static UDSErr_t handle_led_control(UDSServer_t *srv, void *data) {
UDSWDBIArgs_t *args = (UDSWDBIArgs_t *)data;
if (args->dataId == 0x0100) {
// 执行业务逻辑...
return UDS_PositiveResponse;
}
return UDS_NRC_RequestOutOfRange; // 传递给责任链中的下一个处理者
}
/* 静态定义服务节点 */
RTT_UDS_SERVICE_DEFINE(led_node, UDS_EVT_WriteDataByIdent, handle_led_control);步骤 2: 初始化与注册
创建 UDS 实例并注册您的服务节点。
rtt_uds_config_t cfg = {
.can_name = "can1",
.phys_id = 0x7E0,
.func_id = 0x7DF,
.resp_id = 0x7E8,
.func_resp_id = UDS_TP_NOOP_ADDR,
.thread_name = "uds_task",
.stack_size = 2048,
.priority = 12,
.rx_mq_pool_size = 32
};
rtt_uds_env_t *env = rtt_uds_create(&cfg);
rtt_uds_service_register(env, &led_node);步骤 3: 投递 CAN 数据
在您的 CAN 接收回调中,读取数据并投递给协议栈。
static rt_err_t can_rx_callback(rt_device_t dev, rt_size_t size) {
struct rt_can_msg msg;
if (rt_device_read(dev, 0, &msg, sizeof(msg)) == sizeof(msg)) {
rtt_uds_feed_can_frame(env, &msg); // 非阻塞调用,可在 ISR 中使用
}
return RT_EOK;
}examples 目录包含一个完整的可运行示例 (app_uds_example.c)。它提供了 MSH 命令来启动/停止 UDS 服务器。
在 MSH 中使用:
msh > uds_example start can1
UDS Started on can1.使用 Linux cansend 测试:
# 发送 0x2E 写数据指令到 DID 0x0001,值为 0x01
cansend can0 7E0#042E000101- 维护者: wdfk-prog
- 主页: https://github.com/wdfk-prog/can_uds
- 邮箱: [email protected]