Metadata-Version: 2.4
Name: autodoip
Version: 0.1.6
Summary: DoIP (Diagnostics over IP) transport layer for automotive UDS — ISO 13400
Project-URL: Homepage, https://github.com/leno166/autodoip
Project-URL: Source, https://github.com/leno166/autodoip
Author: leno augenstern
License: MIT
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Networking
Requires-Python: >=3.14
Description-Content-Type: text/markdown

# autodoip

**autodoip** 是一个零依赖、纯 Python 实现的 DoIP (Diagnostics over IP) 传输层，严格遵循 ISO 13400 标准，适用于汽车 UDS (Unified Diagnostic Services) 诊断通信。

采用 **Tester-as-Server** 拓扑：Tester 监听单一端口，所有 ECU 主动连接至此端口，帧路由通过 DoIP 头中的逻辑地址完成。

## 特性

- 完全符合 ISO 13400 帧格式（版本反码、Payload Type、地址校验）
- 自动连接管理、空闲超时与断连自动重连
- 重连成功后抛出 `ReconnectionError`，由上层决定是否重发（适配有状态诊断会话）
- 支持多帧响应迭代（例如 0x7F … 0x78 延迟指示）
- 线程安全的状态切换与收发
- 零外部依赖，仅使用 Python 标准库

## 安装

```bash
pip install autodoip
```

要求 Python ≥ 3.14。

## 快速开始

```python
from autodoip import Endpoint

# 创建端点：监听 192.168.10.1:13400，预定义两个 ECU
endpoint = Endpoint(
    ip="192.168.10.1",
    ecus={
        0x1301: ("192.168.10.10", 0),  # port=0 表示不校验端口
        0x1302: ("192.168.10.20", 13400),
    },
)

endpoint.start()  # 开始接受 ECU 连接

# 查看连接状态
print(endpoint.connections)
# {0x1301: ('192.168.10.10', 0, True), 0x1302: ('192.168.10.20', 13400, False)}

# 切换到已连接的 ECU 并发送诊断请求
endpoint.select(0x1301)
for resp in endpoint.conversation(bytes.fromhex("22FF00")):
    print(resp.hex(" "))

# 处理断连重连（适用于有状态诊断会话）
from autodoip import ReconnectionError

try:
    for resp in endpoint.conversation(bytes.fromhex("22FF00")):
        print(resp.hex(" "))
except ReconnectionError:
    # 连接已恢复，但 ECU 状态已重置（会话、安全访问等）
    # 上层需重新同步状态后重试
    pass
```

## 命令行工具

安装后可直接通过 `python -m autodoip` 发送单次诊断请求：

```bash
python -m autodoip \
    --ecu 0x1301 \
    --ecu-ip 192.168.10.10 \
    --payload 22FF00
```

所有参数说明可通过 `--help` 查看。

## API 概览

| 类/函数 | 说明 |
|---|---|
| `Endpoint(ip, ecus, port=13400, tester=0x0E80, config=None)` | DoIP 端点，`ip` 与 `ecus` 必填 |
| `Endpoint.start()` | 启动监听，幂等；需重启则新建实例 |
| `Endpoint.select(addr) -> bool` | 切换当前 ECU；未连接或操作冲突时返回 `False` 且不改变选中 |
| `Endpoint.conversation(payload) -> Iterator[bytes]` | 发送 UDS 载荷，返回响应迭代器。断连自动重连：成功抛 `ReconnectionError`，失败抛 `ConnectionError` |
| `Endpoint.current -> int \| None` | 当前选中的 ECU 逻辑地址 |
| `Endpoint.connections -> dict` | `{addr: (ip, port, connected), ...}` |
| `Config(...)` | 传输调优参数（见下方） |
| `ProtocolError` | 帧校验失败时抛出的异常 |
| `ReconnectionError` | 断连重连成功后抛出，继承 `ConnectionError`。上层可据此重新同步 ECU 状态后重试 |

## 配置

```python
from autodoip import Config, Endpoint

config = Config(
    accept_timeout=1.5,   # accept 超时 (秒)
    p6_timeout=0.05,      # 单次 recv 超时 (秒)
    p6_star_timeout=5.0,  # 整体接收窗口超时 (秒)
    listen_count=5,       # socket listen backlog
    version=0x02,         # DoIP 协议版本
    msg_type=0x8001,      # Payload Type
    byte_order="big",     # 字节序 ("big" / "little")
)

# 将配置传入 Endpoint
endpoint = Endpoint(
    ip="192.168.10.1",
    ecus={
        0x1301: ("192.168.10.10", 0),
        0x1302: ("192.168.10.20", 13400),
    },
    config=config,
)
```

## 许可证

MIT License
