一、项目背景
在汽车电子诊断开发过程中,UDS(Unified Diagnostic Services,统一诊断服务)是 ECU 诊断、刷写与标定的核心协议。无论是产线 EOL 测试,还是研发阶段的联调,都离不开一套稳定、好用的 UDS 诊断工具。
为了满足日常诊断调试需求,我基于 Python + PyQt5 自研了一款同时支持 ZLG 与 Vector 两套主流 CAN 硬件桌面端诊断上位机 ——UDS_Diagnosis。
本项目具有以下特点:
- 轻量:单机即可运行,无复杂依赖;
- 双硬件后端:同时支持 ZLG 与 Vector 两套主流 CAN 硬件,一套代码无缝切换,无需更换工具即可适配不同测试环境;
- 功能聚焦:覆盖诊断开发中最常用的 UDS 服务与工程化能力;
- 多规格分发:独立 exe、绿色免安装版、安装包三种打包形态。
二、功能特性
2.1 硬件与协议支持
| 类别 | 支持项 |
|---|---|
| ZLG 设备 | USBCANFD-200U / 100U / MINI / 400U / 800U、USBCAN-2E-U 等 |
| Vector 设备 | VN16xx 系列 |
| 帧类型 | 标准 CAN、CAN-FD(含 BRS)、CAN-FD(无 BRS) |
| 波特率 | CAN:125K / 250K / 500K / 1M;CAN-FD:仲裁域与数据域独立配置 |
设备接入采用自动扫描机制:启动后自动枚举在线设备,实时刷新(插拔即识别),并对已打开通道做去重与状态管理,避免重复打开同一通道。
双硬件后端是本工具的核心亮点之一:通过统一的CanInterface抽象层,ZLG 与 Vector 两套硬件在应用层完全透明,上层 UDS / ISO-TP 逻辑无需感知底层差异。无论是产线使用 ZLG 设备,还是研发联调使用 Vector VN16xx,都能用同一套界面和诊断流程完成工作,显著降低环境切换成本。
2.2 UDS 诊断服务
封装了日常诊断最常用的一整套 UDS 服务:
- 诊断会话控制(0x10):默认会话 / 扩展会话 / 编程会话切换
- ECU 复位(0x11):硬复位 / 软复位
- Tester Present(0x3E):诊断在线保持
- 读取数据标识符(0x22):按 DID 读取数据,支持常用 DID 快捷指令
- 写入数据标识符(0x2E):按 DID 写入数据
- 安全访问(0x27):支持 GenerateKeyEx / compute_key 算法 DLL、AES-CBC 算法
- 例程控制(0x31):启动 / 停止 / 请求结果
- 清除诊断信息(0x14):清除 DTC
- 读取 DTC 信息(0x19):多种子功能(按状态掩码读数量 / 读 DTC / 读快照等)
其中0x19 读取 DTC支持对响应报文进行结构化解析,自动翻译状态字节、严重度、故障计数等字段。
2.3 工程化能力
- ISO-TP 多帧传输:自动完成单帧 / 首帧 / 连续帧 / 流控帧处理
- 自定义诊断序列:支持分组管理、循环发送、抑制响应、发送间隔设置
- DBC 解析:加载 DBC 文件后,报文信号实时解析显示
- 报文记录与导出:实时追踪收发报文,支持 ASC 格式导出
- 多通道多窗口:同一设备多个通道、多台设备可并行打开,独立监控
- 界面自适应:窗口无级缩放,Ctrl + 滚轮全局缩放字体与控件
三、系统架构
3.1 分层设计
整体采用分层架构,自下而上依次为:
┌─────────────────────────────┐ │ gui 层 │ PyQt5 界面:设备连接、报文追踪、UDS 面板、诊断序列 ├─────────────────────────────┤ │ uds 层 │ UDS 客户端与常用诊断服务封装 ├─────────────────────────────┤ │ isotp 层 │ ISO 15765-2 传输协议 ├─────────────────────────────┤ │ can 层 │ 硬件后端抽象:ZLG / Vector └─────────────────────────────┘3.2 模块说明
| 模块 | 路径 | 职责 |
|---|---|---|
| CAN 抽象 | udstool/can/ | 统一 CAN 收发接口CanInterface,消息结构CanMessage |
| ZLG 后端 | udstool/can/zlg.py | 通过 ctypes 调用 zlgcan.dll |
| Vector 后端 | udstool/can/vector.py | 通过 ctypes 调用 vxlapi.dll |
| ISO-TP | udstool/isotp/transport.py | 多帧传输、流控 |
| UDS 客户端 | udstool/uds/client.py | 常用诊断服务封装 |
| DBC 解析 | udstool/dbc/parser.py | DBC 文件解析与信号提取 |
| 安全算法 | udstool/gui/security_dll.py | Seed&Key 算法 DLL 加载 |
四、核心实现
4.1 设备接入(ctypes 调用 zlgcan.dll)
ZLG 硬件通过 ctypes 直接调用厂商提供的zlgcan.dll,关键帧结构使用ctypes.Structure定义:
class ZCAN_CAN_FRAME(Structure): _fields_ = [ ("can_id", c_uint, 29), ("err", c_uint, 1), ("rtr", c_uint, 1), ("eff", c_uint, 1), ("can_dlc", c_ubyte), ("__pad", c_ubyte), ("__res0", c_ubyte), ("__res1", c_ubyte), ("data", c_ubyte * 8), ]设备打开流程如下:
def open(self): self._setup_prototypes() self._dev_handle = self._dll.ZCAN_OpenDevice(self._dev_type, self._dev_index, 0) self._configure_channel_properties() self._init_channel() self._dll.ZCAN_StartCAN(self._chn_handle) self._start_rx_thread()4.2 ISO-TP 传输
ISO-TP 层实现了 ISO 15765-2 的多帧传输,发送时按数据长度自动选择帧类型:
def _send_payload(self, payload, timeout): n = len(payload) if n <= 7: # 单帧 self._tx(bytes([n]) + payload) return # 首帧 + 连续帧 self._tx(bytes([0x10 | (n >> 8), n & 0xFF]) + payload[:6]) ...4.3 UDS 客户端
UDS 客户端封装了常用服务,并处理 0x78(响应待定)等负响应逻辑:
class UdsClient: def request(self, data, timeout=None): resp = self._tp.request(bytes(data), timeout) # 响应待定(0x78)处理:继续等待 ECU 最终响应 while resp and len(resp) >= 3 and resp[0] == 0x7F and resp[2] == 0x78: resp = self._tp.receive_response(...) if resp and resp[0] == 0x7F: raise UdsError(resp[1], resp[2]) return resp4.4 安全访问算法
安全访问(0x27)支持两种 Seed&Key 算法:
- GenerateKeyEx:Vector / CANoe / TSMaster 标准接口
- compute_key:简化接口
通过解析 PE 导出表自动识别算法函数,并做架构位宽校验:
class SecurityDll: def __init__(self, path, function_name=None, variant="", key_len=8): self._dll = ctypes.CDLL(path) exports = list_exports(path) self.function_name = function_name or self._pick_function(exports) self._setup_prototype()4.5 设备扫描与多通道
设备扫描采用「打开设备 → 获取真实硬件信息 → 去重 → 关闭」的策略,并对共享句柄、通道去重做了专项处理,解决多通道并行打开时的驱动状态冲突。
五、使用说明
5.1 连接设备
- 启动程序,自动弹出设备连接对话框;
- 下拉框自动列出在线设备与通道;
- 选择设备型号、通信模式(标准 CAN / CAN-FD)、波特率;
- 点击「连接」进入主界面。
5.2 发送诊断指令
- 在右侧 UDS 面板选择或输入诊断指令;
- 点击发送,下方日志区实时显示 Tx / Rx;
- 报文追踪面板同步显示 CAN 帧与时间戳。
5.3 序列发送
- 切换到序列面板,可拖拽诊断指令到序列;
- 设置每个步骤的发送次数、间隔、抑制响应;
- 点击发送,序列按顺序循环执行。
5.4 多通道并行
通过状态栏「设备连接」菜单可打开新连接,每开一个通道即新开一个独立窗口,互不干扰。
六、打包发布
使用 PyInstaller 打包,配合 Inno Setup 生成安装程序,输出三种规格:
- 独立 exe:单文件,双击即用;
- 绿色免安装版:解压即用,免安装;
- 安装包:Inno Setup 生成的标准安装程序。
七、总结与展望
这款工具把 UDS 诊断调试的常用能力集成到一个轻量、开箱即用的桌面程序里,显著提升了日常诊断与联调效率。
后续计划继续完善:
- 刷写流程(0x34 / 0x36 / 0x37 下载服务)
- 安全算法插件化
- 诊断脚本可视化编排
- 更多 CAN 硬件后端接入
欢迎交流指正。