autouds
autouds 是一个基于 Python 的 UDS (Unified Diagnostic Services) 诊断工具,遵循 ISO 14229-1 标准,通过 autodoip (ISO 13400) 传输层与汽车 ECU 进行诊断通信。
采用生成器驱动的装饰器模式,将 Python 方法映射为 UDS 服务调用,自动处理请求构造、响应解析和负响应异常。
特性
- 覆盖 ISO 14229-1 主要诊断服务:会话控制、安全访问、DTC 读写、数据标识符读写、例行程序控制等
- 装饰器驱动:
@handler(service_name='session')将生成器方法映射到 UDS 服务 - 生成器模式:
yield发送请求,接收Response后继续处理;负响应通过gen.throw(UdsError)注入生成器 - 逃生舱:
request(raw)接受原始 hex 字符串,绕过校验链直接发送任意报文 - 智能请求构造:支持中文/英文/短键名解析服务 ID 和子功能
- 自动处理延迟响应 (NRC 0x78) 的轮询等待
- 分级日志标签:
[意图保证]/[涌现能力]/[约束补偿]/[隐含依赖]覆盖完整交互链路 - 基于 autodoip 零依赖传输层
安装
pip install autouds
autodoip 和 pydantic 会作为依赖自动安装。要求 Python ≥ 3.14。
快速开始
from autouds import App
# 创建诊断应用:监听指定 IP,预定义 ECU 列表
app = App(
ip='192.168.10.1',
ecus={
'mcu': (0x1001, '192.168.10.10', 13400),
'soc': (0x1002, '192.168.10.20', 13400),
},
)
# 进入默认会话,获取 P2/P2* 定时参数
p2, p2_star = app.session(sub_fn_name='default')
print(f'P2={p2}ms, P2*={p2_star}ms')
# 安全访问 — 请求种子
seed = app.unlock(0x01)
print(f'seed: {seed.hex()}')
# ... 计算密钥 ...
app.unlock_ex(0x01, key)
# 读取数据标识符
data = app.read_did(0xFF00)
print(f'DID 0xFF00: {data.hex()}')
# 切换到另一个 ECU
app.on('soc')
# 逃生舱:发送任意 hex 报文
resp = app.request('10 01')
print(resp.hex)
命令行
python -m autouds [ECU_IP]
支持的 UDS 服务
通用请求(逃生舱)
| 方法 | 说明 |
|---|---|
app.request(raw) |
发送 hex 字符串报文,首字节 = SID,剩余 = params。绕过校验链 |
request() 不校验服务名/子功能名,sub_fn 需自行编码在 raw 中。适合调试、发送未封装的服务。
诊断会话控制 (0x10)
app.session(*, sub_fn_name='default', suppress_positive_response=False) -> tuple[int, int]
| sub_fn_name | 子功能 | 说明 |
|---|---|---|
'default' |
0x01 | 默认会话,返回 (P2, P2*) |
'program' |
0x02 | 编程会话 |
'extend' |
0x03 | 扩展会话 |
'safety' |
0x04 | 安全系统会话 |
ECU 复位 (0x11)
app.reset(*, sub_fn_name='hard', suppress_positive_response=False) -> Response
| sub_fn_name | 子功能 | 说明 |
|---|---|---|
'hard' |
0x01 | 硬复位 |
'key' |
0x02 | 钥匙复位 |
'soft' |
0x03 | 软复位 |
'on' |
0x04 | 启用快速断电 |
'off' |
0x05 | 禁用快速断电 |
安全访问 (0x27)
app.unlock(level, suppress_positive_response=False) -> bytes # 请求种子
app.unlock_ex(level, payload, suppress_positive_response=False) # 发送密钥
level 为安全等级(0x01 / 0x05 / 0x19),unlock_ex 内部自动 level+1 作为密钥发送的子功能。
| 调用 | 报文 | 说明 |
|---|---|---|
app.unlock(0x01) |
27 01 |
请求 L1 种子,返回 seed bytes |
app.unlock_ex(0x01, key) |
27 02 <key> |
发送 L1 密钥 |
app.unlock(0x05) |
27 05 |
请求 L5 种子 |
app.unlock_ex(0x05, key) |
27 06 <key> |
发送 L5 密钥 |
app.unlock(0x19) |
27 19 |
请求 L19 种子 |
app.unlock_ex(0x19, key) |
27 1A <key> |
发送 L19 密钥 |
抑制肯定响应时 unlock() 返回 b''。
通讯控制 (0x28)
app.comm_control(rx=True, tx=True, plus=False, type='app', sub_net=0x0,
suppress_positive_response=False) -> Response
用三个布尔开关选择子功能:
| rx | tx | plus | 子功能 | 说明 |
|---|---|---|---|---|
| T | T | F | 0x00 | 启用接收和发送 |
| T | F | F | 0x01 | 启用接收,禁用发送 |
| F | T | F | 0x02 | 禁用接收,启用发送 |
| F | F | F | 0x03 | 禁用接收和发送 |
| T | F | T | 0x04 | 启用接收(增强),禁用发送 |
| T | T | T | 0x05 | 启用接收和发送(增强) |
type 指定报文类型:'app'(应用报文)、'nm'(网络管理)、'all'(两者)。sub_net 为子网号(0x0~0xF,0xF = 所有子网)。
待机握手 (0x3E)
app.present(*, suppress_positive_response=True) -> Response
默认抑制肯定响应(3E 80),传 False 得 3E 00。
控制 DTC 设置 (0x85)
app.dtc_on(*, suppress_positive_response=False) -> bool
app.dtc_off(*, suppress_positive_response=False) -> bool
| 方法 | 报文 | 说明 |
|---|---|---|
app.dtc_on() |
85 01 → C5 01 |
允许 DTC 更新,返回 True/False |
app.dtc_off() |
85 02 → C5 02 |
禁止 DTC 更新,返回 True/False |
负响应时内部捕获 UdsError,返回 False。
清除诊断信息 (0x14)
app.clear_dtc(mask='FFFFFF') -> bool
mask 为 3 字节 hex 字符串,指定要清除的 DTC 分组(默认 'FFFFFF' 全部清除)。负响应返回 False。
读取 DTC 信息 (0x19)
⚠️ 以下方法尚未实现,仅保留签名预留。
app.read_dtc_count() # TODO: 需要 status mask 参数
app.read_dtc_by_mask() # TODO: 需要 status mask、DTC mask 参数
数据读写 (0x22 / 0x2E)
app.read_did(did) -> bytes # 按标识符读取数据
app.write_did(did, payload) -> None # 按标识符写入数据
read_did 自动校验响应中的 DID 回显,返回 params[2:](去掉回显 DID 后的数据体)。
例行程序控制 (0x31)
app.routine(*, routine_id, sub_fn_name, data=b'',
suppress_positive_response=False) -> Response
| sub_fn_name | 子功能 | 说明 |
|---|---|---|
'start' |
0x01 | 启动例行程序 |
'stop' |
0x02 | 停止例行程序 |
'poll' |
0x03 | 请求执行结果 |
例:app.routine(routine_id=0x0237, sub_fn_name='start', data=glid) → 31 01 02 37 <glid>
未实现的服务
⚠️ 以下方法标记为 TODO,调用会返回
None(生成器体为...)。
| 方法 | 服务 | 说明 |
|---|---|---|
app.io_control() |
0x2F | I/O 控制 — 需要 DID、控制参数 |
app.request_download() |
0x34 | 请求下载 — 需要内存地址、大小 |
app.request_upload() |
0x35 | 请求上传 — 需要内存地址、大小 |
app.transfer_data() |
0x36 | 数据传输 — 需要 block_counter、数据 |
app.exit_transfer() |
0x37 | 退出传输 — 可能需要参数 |
API 概览
| 类/函数 | 说明 |
|---|---|
App(ip, ecus, port=13400, tester=0x0E80, doip_config=None) |
诊断应用主类 |
App.on(name) |
切换到指定 ECU |
App.close() |
关闭 DoIP 连接 |
App.request(raw) |
逃生舱,发送任意 hex 报文 |
handler(service_name=..., sub_fn_name=..., s_id=..., sub_fn=..., suppress_positive_response=...) |
装饰器,将生成器方法映射为 UDS 服务 |
Request |
UDS 请求模型,支持语义名或原始 ID 构造 |
Response |
UDS 响应模型,自动解析正/负响应,支持多帧串联 |
UdsError |
负响应异常,包含 resp.nrc 和 resp.nrc_desc |
自定义服务
通过 @handler 装饰器和 App 子类可以扩展自定义 UDS 服务:
from autouds import App, handler, Response
from typing import Generator
class MyApp(App):
@handler(service_name='read_did')
def read_vin(self, did: int) -> Generator[bytes, Response, bytes]:
resp: Response = yield did.to_bytes(2, 'big')
return resp.params
装饰器支持直接指定 service_id / sub_fn:
@handler(s_id=0x22)
def custom_service(self, did: int) -> Generator[bytes, Response, bytes]:
resp: Response = yield did.to_bytes(2, 'big')
return resp.params
依赖
许可证
MIT License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file autouds-0.3.0.tar.gz.
File metadata
- Download URL: autouds-0.3.0.tar.gz
- Upload date:
- Size: 48.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
750d111b37a4d2d9b68a569fb50b6d029795f94252fa9fa285bb18717209f802
|
|
| MD5 |
f735290d425ad3d82bb345984c388d63
|
|
| BLAKE2b-256 |
5a72b7fb90051e782f9dd3285f71c6079880e84533f177729b6d3c7a59e131cb
|
File details
Details for the file autouds-0.3.0-py3-none-any.whl.
File metadata
- Download URL: autouds-0.3.0-py3-none-any.whl
- Upload date:
- Size: 19.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f3a7cb7faf49b15388b8aa8c2e0675b0659fc382128137dc663b294fa565cdb
|
|
| MD5 |
9c2b95e3f205b34eb8941b62307600ab
|
|
| BLAKE2b-256 |
4f5be6c429b004f0a88b9a22ceb40b8746805ccef8e68375b4224c09af86ec7f
|