01. SOVD 协议原理与标准背景
1. 背景与原理
1.1 标准族:ISO 17978 系列(2026 年发布)
| 部分 | 正式标题 | 状态 |
|---|---|---|
| ISO 17978-1:2026 | Road vehicles --- Service-oriented vehicle diagnostics (SOVD) --- Part 1: General information, definitions, rules and basic principles | 2026-05 发布,第 1 版,13 页,ISO/TC 22/SC 31 |
| ISO 17978-2:2026 | Part 2: Use cases definition | 2026 年发布 |
| ISO 17978-3:2026 | Part 3: Application programming interface (API) | 2026-03 发布(本项目直接实现对象) |
Part 1 的官方范围摘要(ISO 官网):
This document: gives an overview of the ISO 17978 series; specifies rules and basic principles for the service-oriented vehicle diagnostics (SOVD), conforming to the extended vehicle (ExVe) methodology, as specified in the ISO 20077 series; defines general terms.
三个关键点:
- 遵循扩展车辆(ExVe)方法学 ISO 20077 ------ SOVD 不是孤立的诊断协议,而是"扩展车辆"体系的一部分。ExVe 解决的是「车辆数据如何在车端、云端、第三方之间受控流转」的治理问题,SOVD 是其在诊断域的 API 落点。
- 2026 年才发布第 1 版 ------ 这是非常新的标准,本项目是与标准同步演进的早期实现(也解释了功能完成度低)。
- Part 3 的范围 (标准摘要):定义 SOVD API,用于标准化 HPC(高性能计算单元)与传统 ECU 的诊断方法、检索诊断能力、发现扩展车辆中的 SOVD 服务;API 功能包含故障访问(读取故障条目、读取环境数据)等。
1.2 为什么需要 SOVD:从 UDS 到面向服务
| 维度 | 经典 UDS(ISO 14229) | SOVD(ISO 17978-3) |
|---|---|---|
| 交互模型 | 请求/响应式服务原语(0x22 读数据、0x2E 写数据、0x19 读 DTC、0x31 例程、0x34~0x37 刷写) | HTTP REST 资源 + JSON |
| 寻址 | 物理/功能寻址 + ECU 地址 + 专有传输(CAN/ISO-TP、DoIP) | URL 路径 /sovd/v1/components/{id}/data/{data_id} |
| 拓扑 | 静态描述(ODX/PDX 数据库离线加载) | 运行时可发现:实体集合 + 能力自描述 + 发现机制 |
| 软件实体 | 只有 ECU | 一等公民 App(Component 上运行的软件),适配 HPC 上"一硬件多软件" |
| 工具链 | 专用诊断仪 + ODX 运行时 | 任意 HTTP 客户端、curl、浏览器、LLM(MCP) |
| 消费者 | 售后诊断仪 | 车端、云端、远程诊断、CI、AI Agent |
驱动因素(基于 Part 3 范围与项目生态):中央计算/HPC 架构使得"ECU 数量"与"软件实体"解耦;软件定义汽车需要远程、批量、自动化的诊断能力;云原生工具链(HTTP/JSON/OpenAPI)可直接使用,不再依赖车载专有的 ODX 栈。
1.3 资源模型:Areas / Components / Apps / Functions
层级(来自 opensovd-cli/mcp/src/main.rs 的 server instructions):
Areas > Components > Apps > Functions
| 实体 | 含义 | 关系字段 |
|---|---|---|
| Area | 整车架构的逻辑视图(域 / 区,如 powertrain、network) | ------ |
| Component | 硬件单元(ECU / HPC 板) | area_id(belongs-to) |
| App | 运行在 Component 上的软件 | is_located_on(宿主 Component,恰 1 个)、area_id(可选) |
| Function | 跨实体的功能视图(根级集合) | 本仓库仅有 href 字段,未实现 |
关系语义:
is-located-on:App → 其宿主 Component(apps/{id}/is-located-on),恰好 1 个hosts:Component → 其上运行的 Apps(components/{id}/hosts)belongs-to:Component/App → 所属 Area,0 或 1 个contains:Area → 其包含的 Components 和 Appssubcomponents/subareas/depends-on:字段存在,未实现
1.4 能力集合(capabilities)
EntityCapabilities 是 SOVD 的"能力广告牌"------客户端通过它知道"这个实体能干什么、下一步去哪"。完整字段(opensovd-models/src/discovery.rs:52-157,注释中按 C1~C5 条件分组):
| 分组 | 能力 | 含义 / 经典对应 |
|---|---|---|
| C1 资源集合 | data |
数据资源读写(UDS 0x22/0x2E) |
data-lists |
预定义数据项列表,一次读多项以减少往返 | |
faults |
故障内存 / DTC(UDS 0x19) | |
operations |
可执行操作 / 例程(UDS 0x31) | |
configurations |
变体配置 / 编码 | |
bulk-data |
大块数据传输(刷写、日志下载,UDS 0x34~0x37) | |
updates |
软件更新 | |
modes |
ECU 模式 / 会话(UDS 0x10/0x11/0x28) | |
| C2 引用集合 | locks |
资源互斥锁(多客户端并发) |
logs、communication-logs |
事件日志、诊断通信审计 | |
cyclic-subscriptions |
周期性订阅/推送,替代轮询采样 | |
scripts、triggers |
服务端脚本、事件触发 | |
belongs-to、contains、hosts、is-located-on、depends-on |
关系引用 | |
| C3 | variant |
变体标识 |
| C4 根级集合 | areas、components、apps、functions |
仅根实体出现 |
| C5 子集合 | subcomponents、subareas |
层级嵌套 |
data 的四类分类 (opensovd-models/src/data.rs):
identData------ 固定标识参数(零件号、VIN、软件版本),只读currentData------ 动态测量值(电压、温度),只读storedData------ 参数,可读可写sysInfo------ 动态系统资源(CPU 负载),只读x-<ext>-*------ 自定义扩展前缀
1.5 API 约定
版本化与发现
GET /sovd/version-info ← 故意不在 /v1 下:版本发现必须先于版本化访问
GET /sovd/v1/... ← 版本化业务资源
version-info 响应:
json
{ "sovd_info": [ { "version": "1.1",
"base_uri": "http://127.0.0.1:7690/sovd/v1",
"vendor_info": { "version": "0.1.1", "name": "OpenSOVD" } } ] }
客户端侧对应标准"版本协商"模式:Discovery(版本无关)→ 读 version-info → select(|s| s.version == "1.1") → 得到绑定该版本的 Client。
HATEOAS :每个 capabilities 响应是一张"下一步可去哪"的链接表,href 为绝对 URI,客户端无需拼装路径、可纯靠链接遍历。
include-schema :几乎所有 GET 支持 ?include-schema=true,响应在 schema 字段内联返回 JSON Schema(由 schemars 生成),便于客户端自动生成类型与校验。
错误模型 GenericError(opensovd-models/src/error.rs):
jsonc
{ "error_code": "...", // 必填,kebab-case
"vendor_code": "...", // 可选
"message": "...", // 必填
"translation_id": "...", // 可选
"parameters": { } } // 可选
ErrorCode 全部 15 个取值:error-response、incomplete-request、insufficient-access-rights、invalid-response-content、invalid-signature、lock-broken、not-responding、precondition-not-fulfilled、sovd-server-failure、sovd-server-misconfigured、update-automated-not-supported、update-execution-in-progress、update-preparation-in-progress、update-process-in-progress、vendor-specific。
注意
lock-broken与 4 个update-*码的存在:标准明确设计了并发锁 与软件更新场景,而本仓库两者均未实现。
1.6 架构角色:server / gateway / client
- SOVD server :持有一份实体集合,对外提供
/sovd/v1。可以是 ECU 内嵌、车内 HPC、或云端。 - SOVD client:消费 API,支持版本协商。
- SOVD gateway :聚合层 ------把多个下游 SOVD server 的实体汇聚成统一视图。本项目的聚合机制是
DiscoveryProvider(见 04)。
1.7 与 UDS / DoIP / OBD 的关系
- 本仓库不含任何 UDS/DoIP/OBD 协议栈代码 :
OBD仅作为数据项的一个 tag 出现。即opensovd-core是纯 HTTP/JSON 层。 - 生态仓库揭示连接方式 (同组织):
uds2sovd-proxy(UDS↔SOVD 协议转换代理)、classic-diagnostic-adapter(经典诊断适配器)、odx-converter(ODX→SOVD 描述转换)、fault-lib、dlt-tracing-lib(对应 logs 能力)。
SOVD 不复用 UDS 服务原语,而是拥有独立资源模型;遗留 UDS ECU 需经由代理/适配器接入 SOVD 世界。对应关系:
| SOVD 能力 | 经典对应 |
|---|---|
data(ident/current/stored/sysInfo) |
UDS 0x22 / 0x2E |
faults |
UDS 0x19 + SAE J2012 DTC 格式 |
operations |
UDS 0x31 |
modes |
UDS 0x10 / 0x11 / 0x28 |
bulk-data |
UDS 0x34~0x37 |
locks |
UDS 无直接对应(SOVD 新引入,多客户端并发所需) |
2. 当前实现架构:协议要素 → 代码落点
| 协议要素 | 代码落点 | 状态 |
|---|---|---|
版本发现 /version-info |
opensovd-server/src/routes/version.rs |
✅ |
实体集合 /components /apps /areas |
opensovd-server/src/routes/entities/* |
✅ |
能力自描述 EntityCapabilities |
opensovd-models/src/discovery.rs(22 字段全定义) |
⚠️ 仅填 4 组 |
| 关系路由 hosts/belongs-to/is-located-on/contains | routes/entities/{component,app,area}.rs |
✅ |
| data 读写 + categories/groups | routes/data.rs + opensovd-core/src/data.rs |
✅ |
错误模型 GenericError + 15 个 error_code |
opensovd-models/src/error.rs、routes/error.rs |
⚠️ 仅用 5 个 |
| include-schema | opensovd-server/src/schema.rs |
✅ |
发现/聚合 DiscoveryProvider |
opensovd-core/src/discovery.rs、server.rs::run_discovery |
⚠️ 仅 trait + 测试 mock |
| faults / operations / configurations / bulk-data / modes / locks / logs / updates / subscriptions | ------ | ❌ 全部未实现 |
| 单位模型 | opensovd-extra/src/unit.rs |
⚠️ 有模型无换算函数 |
一句话:协议骨架(版本、实体、关系、数据、错误、schema)已落地,协议肌肉(故障、例程、配置、刷写、模式、锁、日志、订阅)尚未生长。
3. 核心流程与算法:一次标准 SOVD 访问
3.1 版本协商流程(客户端视角)
Client::builder().base_uri("http://host/sovd")
└─> Discovery::versions::<VendorInfo>()
├─ GET {base}/version-info (OnceCell 缓存,同会话只取一次)
├─ 解析 Vec<SovdInfo<V>>
└─ select(|s| s.version == "1.1")
└─ 取 base_uri(已含 /v1)→ 构造绑定版本的 Client
关键点:base_uri 由服务端下发而非客户端拼装,这是 SOVD 支持多版本并存与网关级联的基础。
3.2 能力发现流程(HATEOAS 遍历)
GET /sovd/v1/ → 根能力(areas/components/apps 三个 href,仅当非空时给出)
GET /sovd/v1/components → Vec<EntityReference>{id, name, href, tags}
GET /sovd/v1/components/{id} → EntityCapabilities{id, name, variant, hosts, belongs_to, data, ...}
GET /sovd/v1/components/{id}/hosts → 其上的 Apps
GET /sovd/v1/components/{id}/data → 数据项列表(可按 groups/categories/tags 过滤)
GET /sovd/v1/components/{id}/data/{data_id} → 读值(?include-schema=true 附带 schema)
PUT /sovd/v1/components/{id}/data/{data_id} → 写值(204 / 400 / 404)
客户端可完全靠 href 逐层下钻,无需知道 URL 模板------这就是 HATEOAS 在 SOVD 中的价值(E2E 测试正是这样遍历全 API)。
3.3 网关聚合流程(标准意义的 gateway)
[下游 SOVD server A] ─┐
[下游 SOVD server B] ─┼─> DiscoveryProvider::discover() → Stream<(remove, add)>
[mDNS/SD 发现源 C] ─┘ │
▼
select_all 合并 → 单条写守卫内应用差分
(remove 先于 add,components→apps→areas)
│
▼
共享 Topology ──> /sovd/v1 对外暴露统一视图
这是 SOVD "聚合"角色的核心算法,详见 04 章 §3.4。
4. 待完善与风险
4.1 协议符合性缺口(严重)
- 能力广告不完整 :
EntityCapabilities22 个字段中仅填充id/name/translation_id/variant/hosts/belongs_to/is_located_on/contains/data/areas/components/apps,其余恒为None。对客户端而言,未实现的能力与"该实体不支持"不可区分------标准语义上应该用"字段缺省"表达"不支持",这一点是符合的,但客户端无法区分"不支持"与"未实现"。 functions实体缺失 :根级四集合中functions从未填充,App 之下的 Function 层级完全没有建模。- 无订阅/推送机制 :
cyclic-subscriptions未被实现,也没有 WebSocket/SSE 通道,客户端只能轮询------对于实时数据(currentData)场景是重大缺口。 - 锁与并发控制缺失 :
locks能力与lock-broken错误码均未使用,多客户端并发写无保护。 - 软件更新能力缺失 :4 个
update-*错误码定义了却无对应流程。
4.2 错误处理语义偏差(中)
vendor-specific被滥用 :实体不存在返回vendor-specific+vendor_code: entity-not-found,而标准语义上vendor-specific应留给厂商扩展;更贴切的是error-response或专门的码。- 写只读资源返回 400
error-response:语义上 405 Method Not Allowed 或precondition-not-fulfilled更准确。 - 内部错误一律 500 + 脱敏 :符合安全实践,但缺少
sovd-server-failure/sovd-server-misconfigured的区分使用。 invalid-signature定义了却不校验 :WriteRequest.signature字段被解析后完全忽略,签名/完整性校验链路缺位(安全与合规风险)。
4.3 标准演进跟踪(建议)
- ISO 17978 三部分均于 2026 年发布第 1 版,标准仍在快速演进(Part 1 的生命周期显示 2023-04 立项 → 2026-05 发布)。建议:
- 建立标准条款 → 代码落点的可追溯矩阵(本文件 §2 的表格可作为起点)
- 关注 ExVe(ISO 20077)方法学对数据治理的影响:SOVD 不只是 API,还涉及授权、审计、数据分级
- 生态侧关注
classic-diagnostic-adapter的成熟节奏------它决定了 SOVD 接入存量 UDS ECU 的可行性
5. 关键代码位置
| 内容 | 路径 |
|---|---|
| 能力模型(22 字段) | opensovd-models/src/discovery.rs:52-157 |
| 错误码(15 个)与 GenericError | opensovd-models/src/error.rs:10-78 |
| data 分类(ident/current/stored/sysInfo) | opensovd-models/src/data.rs:10-25 |
| 版本信息与 vendor info | opensovd-models/src/version.rs |
| 实体层级说明(MCP instructions) | opensovd-cli/mcp/src/main.rs:123-131 |
| 标准链接 | opensovd-core/README.md:17 |