介绍
- Diagnostic Service Dispatcher - DSD
- DSD 子模块负责检查传入诊断请求的有效性(诊断会话/安全访问级别/应用程序权限的验证),并跟踪服务请求执行的进度
- DSD 子模块只处理有效的请求,拒绝无效的请求
用例
- 以下是相关用例,详细描述如下:
- 接收请求消息并发送正响应消息
- 接收请求消息并抑制正响应
- 接收请求消息并抑制否定响应
- 接收请求消息并发送否定响应消息
- 发送一个正响应消息,没有相应的请求
- 分段响应
接收请求消息并发送正响应消息
- 这是正常通信(“乒乓”)的标准用例,服务端接收诊断请求消息,DSD 子模块确保请求消息的有效性,在这个用例中,请求是有效的,响应是肯定的
- 请求将被转发到 DSP 子模块中适当的数据处理器,当数据处理器完成所有数据处理动作后,触发 DSD 子模块发送响应消息
- 如果数据处理器作为请求指示函数的一部分立即处理服务,则数据处理器可以触发该指示函数内部的传输(“同步”)
- 如果处理需要较长的时间(例如等待 EEPROM 驱动程序),数据处理器将延迟一些处理(“异步”),响应挂起机制由 DSL 子模块涵盖
- 数据处理器显式地触发传输,但是是从数据处理器的上下文中触发的
- 一旦接收到请求消息,相应的 DcmPduId 就会被 DSL 子模块阻塞,在此请求的处理过程中,不能接收任何其他相同协议类型的请求(例如,可以通过OBD会话结束增强会话),直到发送相应的响应消息并再次释放 DcmPduId
接收请求消息并抑制正响应
- 这是前一个用例的子用例,在 UDS 协议中,可以通过在请求消息中设置一个特殊的位来抑制正响应,这种特殊的抑制处理完全在 DSD 子模块中执行
接收请求消息并抑制否定响应
- 在功能性寻址的情况下,DSD 子模块应抑制 NRC 0x11、0x12、0x31、0x7E 和 0x7F 的否定响应
接收请求消息并发送否定响应消息
- 拒绝请求消息和发送否定响应有许多不同的原因,如果诊断请求无效,或者在当前会话中可能不会执行请求,则 DSD 子模块将拒绝处理并返回否定响应
- 但是拒绝执行格式正确的请求消息的理由甚至有很多,例如:如果 ECU 或系统状态不允许执行。在这种情况下,DSP 子模块将触发一个否定响应,包括 NRC 提供该请求被拒绝的额外信息
- 如果请求由多个参数组成(例如,UDS 服务 ReadDataByIdentifier (0x22)请求有多个标识符需要读取),则每个参数被单独处理。每个参数都会返回一个错误。如果至少有一个参数被成功处理,这种请求将返回一个积极的响应
- DSD 子模块根据 ISO14229-1 对收到的每条诊断请求进行一系列校验, 这一系列的校验若果有一个校验失败了,那么 Dcm 就会停止接下去的校验,然后挺固执执行接收到的诊断请求,并最终发送校验失败的 NRC
发送一个正响应消息,没有相应的请求
- UDS 协议中有两种服务,对一个请求发送多个响应
- 通常,一个服务用于启用(和禁用)由事件或时间触发的另一个服务的传输,该服务再次由 ECU 发送,而不需要相应的请求,这些服务包括:
- UDS 服务 ReadDataByPeriodicIdentifier (0x2A),该服务允许客户端请求定期传输由一个或多个 periodicDataIdentifiers 标识的服务端的数据
- ResponseOnEvent (0x86),此服务请求服务端启动或停止对指定事件的响应传输
- 这种处理特别由 DSL 子模块控制,但是,DSD 子模块还提供了在没有相应请求的情况下生成响应的可能性
分段响应(page -buffer)
- 在诊断协议中,一些服务允许交换大量数据,例如: UDS 服务 ReadDTCInformation (0x19) 和 UDS 服务 TransferData (0x36)
- 在传统方法中,ECU 内部缓冲区必须足够大,以保存要交换的最长数据消息(最坏情况),并且在传输开始之前填满整个缓冲区
- ECU 中的 RAM 内存通常是一个关键资源,特别是在较小的微处理器中,在一种更节省内存的方法中,缓冲区只被部分填充,部分传输,然后部分重新填充,以此类推,这种分页机制显著减少的内存量,但需要定义良好的缓冲区重新填充反应时间
- 用户可以决定是使用“线性缓冲区”还是分页缓冲区进行诊断
DSD 与其他模块的交互
- DSD 子模块在接收到诊断消息时被 DSL 子模块调用,并执行以下操作:
- 将请求的处理委托给 DSP 子模块或 Dcm 之外的外部模块
- 跟踪请求处理(返回 <Module><DiagnosticService>() 和 <Module><DiagnosticService>_<SubService>() API 调用或“服务解释器调用”的状态)
- 将应用程序的响应传输到 DSL 子模块(传输功能)
- DSD 与 DSL 主要功能的交互
方向 | 解释 |
双向 | 诊断消息的交换(接收/发送) |
DSD to DSL | 获取最新的诊断会话和安全级别 |
DSL to DSD | 诊断消息传输确认 |
- DSD 与 DSP 的交互
方向 | 解释 |
DSD to DSP | 委托处理请求 | 诊断消息传输确认 |
DSP to DSD | 处理结束的信号 |
支持检查诊断服务标识和适配诊断消息
- 如果新的诊断消息被识别,DSD 子模块将由 DSL 子模块触发,DSD 子模块将通过分析接收到的诊断消息中包含的诊断服务标识符开始处理
- 如果配置(配置参数 DcmRespondAllRequest=FALSE),如果 Dcm 模块接收到包含 0x40 到 0x7F 或 0xC0 到 0xFF 范围内的服务 ID 的诊断请求,Dcm 将不响应这样的请求
- DSD 子模块根据诊断服务标识符(基于诊断消息的第一个字节)分析和检查诊断消息
- 在检查过程中,DSD 子模块在服务标识表(Service Identifier Table)中搜索新接收到的诊断服务标识,出于性能原因,可能需要使用 “lookup table” 功能来完成支持检查,在此服务标识表中,预定义了 ECU 支持的所有服务标识
- DSL 子模块应提供当前的服务标识表, 该服务标识表和有关支持的服务的信息将由外部配置中生成,可以配置多个服务标识表以供选择,但同时只能有一个服务标识表处于活动状态
- DSD 子模块应扫描活动的服务标识表以获取新收到的诊断服务标识
- 如果支持此服务标识符,并且配置参数 DcmDsdSidTabFnc 不为空,DSD 子模块将调用配置好的服务接口(<Module>_<DiagnosticService>),如果配置参数为空,Dcm将调用内部实现的服务接口
- 如果诊断服务标识符不包含在服务标识表中,则不支持诊断服务标识符,如果新接收到的诊断服务标识符不被支持,DSD 子模块将发送 NRC 0x11(不支持服务)的否定响应到 DSL 子模块
- DSD 子模块应存储新接收到的诊断服务标识符以供以后使用
- 举例:WriteDataByIdentifier(用于写 VIN 号):
- DSL 子模块接收到一条新的诊断消息(0x2E, 0xF1, 0x90, 0x57, 0x30, 0x4C, 0x30, 0x30, 0x30, 0x30, 0x34, 0x33, 0x4D, 0x42, 0x35, 0x34, 0x31, 0x33, 0x32, 0x36)
- DSL 子模块向 DSD 子模块指示新诊断消息,在诊断消息缓冲区中存储诊断消息(buffer=0x2E, 0xF1, 0x90...)
- DSD 子模块根据服务标识符 0x2E(缓冲区的第一个字节)对传入的诊断消息进行检查
- 传入的诊断消息存储在 Dcm 变量 Dcm_MsgContextType 中
- 在 DcmDsdSidTabServiceId 中配置的服务标识符的 Id 在一个 DcmDsdServiceTable 中应该是唯一的
- 对于 <Module>_<DiagnosticService>的第一次调用,opStatus 应该设置为 DCM_INITIAL
- 当 <Module>_<DiagnosticService>() 返回 DCM_E_PENDING 时,Dcm 将不接受其他请求(相同或更低优先级)
- Dcm 内部超时处理(基于 RCR-RP 限制)可能导致取消外部诊断服务处理
- 在进行取消操作时,API <Module>_<DiagnosticService> 被再次调用,参数 opStatus 设置为 DCM_CANCEL
"suppressPosRspMsgIndicationBit" 肯定响应抑制处理
- suppressPosRspMsgIndicationBit 是子函数参数结构的一部分(诊断消息中第二个字节的 bit7)
- 如果 suppressPosRspMsgIndicationBit 为 TRUE,则 DSD 子模块不发送正响应消息
- DSD 子模块将从诊断消息中屏蔽 suppressPosRspMsgIndicationBit 位,即经 DSD 处理过后的消息中 suppressPosRspMsgIndicationBit 位都是为 0 的
- Dcm 模块应通过参数 Dcm_MsgContextType 传输(在层之间)正在活动的正响应的抑制信息
- 在等待响应的情况下,Dcm 模块应清除 suppressPosRspMsgIndicationBit
- 当 Dcm 模块为新接收到的服务标识设置了配置参数 DcmDsdSidTabSubfuncAvail 时,Dcm模块才会进行 suppressPosRspMsgIndicationBit 处理
- suppressPosRspMsgIndicationBit 仅在服务有子服务时可用
验证功能
- 在执行接收到的诊断服务之前,DSD 将执行一系列验证,只有当所有验证都成功通过时,DSD 才会接受服务
- 服务执行前的 DSD 验证,如果以下验证按顺序通过,Dcm 才会处理诊断请求:
- 验证厂家权限(调用厂家接口指示操作)
- 验证 SID
- 验证当前身份验证状态的业务访问控制
- 验证诊断会话
- 验证服务的安全访问等级
- 验证供应商权限(调用供应商接口指示操作)
- 验证服务 ID 的 Mode 规则
- 如果 DSD 生成 NRC, Dcm 应只调用 XXX_Confirmation,这意味着 Dcm 不会调用 DspInternal_DcmConfirmation()
诊断业务访问权限验证
- UDS 鉴权服务 (0x29) 用于修改诊断连接的鉴权状态,并提供接入权限
- 根据到达的角色和提供的白名单,该连接上的诊断仪可以使用一组动态诊断服务
- DSD 子模块在服务 ID (SID) 和子功能 (SF) 级别上验证服务是否可以执行
- Dcm 只对 UDS 服务进行鉴权校验,UDS 服务的服务 ID 取值范围为 0x10 ~ 0xFF
- OBD 服务明确地排除在身份验证检查之外,根据立法,OBD 服务需要始终可用,独立于活动身份验证状态,如果使用 WWH-OBD,系统工程师必须确保这些服务始终是可访问的
- 验证访问权限,如果配置了容器 DcmDspAuthentication,则 Dcm 只会验证和检查诊断服务的配置访问权限
- 如果没有配置 DcmDspAuthentication, Dcm 将授予所有服务访问权限并进行处理
- 检查诊断服务的访问权限是在服务结构的不同级别完成的,诊断服务访问权限的使用引入了允许或拒绝诊断服务的方法
- 一些服务应该始终被允许执行,例如设置当前诊断仪访问权限的服务 0x29 (Authentication),此服务和其他 OEM 或特定于供应商的服务应该具有独立于身份验证状态的访问权限,为了实现这一点,Dcm 使用一个默认角色,该角色用于所有未验证状态,在这种状态下,所有基于角色的验证都在身份验证状态下完成,活动角色由配置提供
- 如果角色验证成功或服务被白名单允许,Dcm 应允许服务执行
- Dcm 应检查当前认证是否允许服务执行,Dcm 应按下列顺序执行下列检查。如果检查授予对服务的访问权限,则跳过其余检查:
- 检查服务 ID 级别
- 检查服务 ID 和子功能级别
- 检查具有一个或多个 DID 的服务
- 检查动态定义的 DID
- 每个子功能检查 0x31 服务
- 检查 0x19 服务参数 MemorySelection
- 在处理诊断服务时,Dcm 应在下列情况下批准访问该诊断服务:
- 对于该服务,通过 DcmDsdServiceRoleRef 配置了服务角色,并且根据 [SWS_Dcm_01522] 验证成功
- 白名单中含有该服务的 SID
- 在处理具有子功能的诊断服务时,Dcm 应在下列情况下批准访问该诊断服务:
- 对于该服务和子功能,通过 DcmDsdSubServiceRoleRef 配置子服务服务角色,并且根据 [SWS_Dcm_01522] 验证成功
- 白名单中含有该服务的子功能号
- 对于 3 字节和 4 字节的服务条目白名单,Dcm 应验证配置的白名单服务元素的完整长度
- 如果接收到的请求的第一个字节匹配整个白名单条目,则授予服务访问权限
- 在 DSD 内验证字节 3 和字节 4 超出了典型 DSD 操作的范围,但 DSD 提供了扩展白名单服务验证功能的方法,并提供了适应保留身份验证解决方案的方法
- 如果服务执行验证失败,Dcm 将发送 NRC 0x34(authenticationRequired),并停止业务处理
诊断会话的验证
- UDS 0x10 服务(DiagnosticSessionControl) 用于在 ECU 上开启不同的诊断会话,诊断会话在 ECU 中启用一组特定的诊断服务或功能
- DSD 模块接收到业务请求后,通过 Dcm_GetSesCtrlType 获取当前诊断会话状态,并验证当前诊断会话中是否允许执行请求的服务 (不是 UDS 0x10 服务 - DiagnosticSessionControl) 和子服务
- 注意 UDS 0x10 服务 - DiagnosticSessionControl 本身不是 DSD 子模块的一部分
- 如果当前诊断会话中不允许新接收的诊断服务,DSD 子模块向 DSL 子模块发送 NRC 0x7F (serviceNotSupportedInActiveSession) 的否定响应
- 如果当前诊断会话允许新接收的诊断服务,但是请求自服务不被允许,DSD 子模块向 DSL 子模块发送 NRC 0x7E (subFunctionNotSupportedInActiveSession) 的负响应
服务安全访问等级的验证
- 安全访问等级处理的目的是提供访问数据或诊断服务的可能性,这些数据和或诊断服务由于安全等原因而受到访问限制
- DSD 子模块通过 UDS 0x27 服务 (SecurityAccess) 执行此操作
- DSD子 模块将使用 DSL 函数 Dcm_GetSecurityLevel 获取当前安全等级,然后验证请求的服务 (非 UDS 0x27 服务 - SecurityAccess) 是否允许在当前安全等级下执行
- 安全等级的管理不是 DSD 子模块的一部分
- 注意:对于某些用例,例如 UDS 0x22 服务 - ReadDataByIdentifier 中有一部分数据的安全等级也较高,也需要调用 Dcm_GetSecurityLevel 获取当前安全等级进行验证
- 如果当前安全等级不允许新接收的诊断服务(根据配置参数DcmDsdSidTabSecurityLevelRef),DSD 子模块应向 DSL 子模块发送 NRC 0x33(安全访问被拒绝) 的否定响应
- 如果当前安全等级允许新接收的诊断服务,但请求的子服务不允许(根据配置参数 DcmDsdSubServiceSecurityLevelRef),DSD 子模块应向 DSL 子模块发送 NRC 0x33(安全访问被拒绝) 的否定响应
服务模式依赖项的验证
- 如果在当前模式条件下不允许新接收的诊断服务(根据配置参数 DcmDsdSidTabModeRuleRef),那么 DSD 子模块将根据 DcmModeRule 计算出的负响应发送给 DSL 子模块
- 如果在当前模式条件下允许新接收的诊断服务,但是请求的子服务不允许(根据配置参数 DcmDsdSubServiceModeRuleRef),那么 DSD 子模块将根据 DcmModeRule 计算出的负响应发送给 DSL 子模块
检查格式和子函数支持
- DSD 子模块在执行请求的命令之前,会检查是否支持指定的子功能
- 如果处理的服务没有配置 DcmDsdSubService,且 DcmDsdSubServiceId 不存在,则 DSD 将发送否定响应 NRC 0x12 (subfunctionNotSupported)
- 不允许对 UDS 0x31 服务 (RoutineControl) 进行 NRC 检查
- DSD 子模块将在执行所请求的命令之前检查最小消息长度,如果请求的长度小于请求的最小长度,DSD 子模块将触发一个 NRC 0x13(错误的消息长度或无效的格式)的否定响应
- 如果为 DcmDsdService 配置了DcmDsdSubService,则 Dcm 应支持 DcmDsdSubServiceId 中配置的子功能
制造商应用程序环境/权限的验证
- 此功能的目的是,在收到诊断请求后,要求制造商应用程序检查权限/环境,例如,在 ECU 的 after-run 状态下,可能不允许处理 OBD 请求
- 如果容器 DcmDsdServiceRequestManufacturerNotification 存在,DSD 子模块将在所有已配置的 ServiceRequestIndication 端口上调用 Xxx_Indication 操作(见配置参数 DcmDsdServiceRequestManufacturerNotification)
- 如果有一个 Xxx_Indication 函数返回 E_REQUEST_NOT_ACCEPTED, DSD 子模块将不给出响应,并且 DSD 只调用 Xxx_Confirmation 而不调用 DspInternal_DcmConfirmation
- 如果有一个 Xxx_Indication 函数返回 E_NOT_OK,并且没有函数返回 E_REQUEST_NOT_ACCEPTED,那么 DSD 子模块将根据 ErrorCode 参数触发一个 NRC 否定响应
- 如果超过一个 Xxx_Indication 函数被调用返回 E_NOT_OK,并且没有返回 E_REQUEST_NOT_ACCEPTED,那么 DSD 子模块将根据第一个返回 E_NOT_OK 的 Xxx_Indication 函数的 ErrorCode 参数 触发一个 NRC 否定响应
供应商应用程序环境/权限的验证
- 此功能的目的是,在处理诊断消息之前,请求供应商应用程序检查权限/环境,例如,在 ECU 的 after-run 状态下,可能不允许处理 OBD 请求
- 如果容器 DcmDsdServiceRequestSupplierNotification 存在,则 DSD 子模块将在所有已配置的 ServiceRequestIndication 端口上调用 Xxx_Indication 操作(见配置参数 DcmDsdServiceRequestSupplierNotification)
- 如果有一个 Xxx_Indication 函数返回 E_REQUEST_NOT_ACCEPTED, DSD 子模块将不给出响应
- 如果有一个 Xxx_Indication 函数返回 E_NOT_OK,并且没有函数返回 E_REQUEST_NOT_ACCEPTED,那么 DSD 子模块将根据 ErrorCode 参数触发一个 NRC 否定响应
- 如果超过一个 Xxx_Indication 函数被调用返回 E_NOT_OK,并且没有返回 E_REQUEST_NOT_ACCEPTED,那么 DSD 子模块将根据第一个返回 E_NOT_OK 的 Xxx_Indication 函数的 ErrorCode 参数 触发一个 NRC 否定响应
向 DSP 子模块分发诊断信息
- DSD 子模块为新接收到的诊断服务标识符搜索 DSP 子模块的可执行功能,并调用相应的 DSP 服务解释程序
- 当 DSP 子模块完成了所请求的诊断服务的执行后,DSD 子模块将进行响应
- 执行 DSP 服务解释程序可以得到两种结果:积极的结果或负面的结果
- 有三种可能的响应:正响应、否定响应、无响应(在抑制响应的情况下)
正响应
- DSD 子模块应在参数 "Dcm_MsgContextType" 中添加响应标识符和响应数据流(由应用程序返回),因此,DSD 子模块应将 Dcm_MsgContextType 传输到(响应)缓冲区中,并在缓冲区的第一个字节处添加服务标识符,DSD 子模块在下一个执行步骤中执行 “发起传输” 功能
否定响应
- DSP 子模块可以触发带有特定 NRC 的否定响应传输到 DSD 子模块
- DSD 子模块将处理所有的 NRC 响应(由应用程序产生的 Dcm_NegativeResponseCodeType)
响应抑制
- 在 Dcm_MsgContextType 中的元素 Dcm_MsgAddInfoType 中有个表示抑制响应的变量 suppressPosRspMsgIndicationBit,如果这个变量置 1,那么 DSD 子模块将激活正响应抑制
- 如果执行结果为负,并且激活了功能寻址,则 DSD 子模块应激活对以下负响应的抑制(即在功能寻址下,以下情况的是不需要响应的):
- NRC 0x11 (服务不支持)
- NRC 0x12 (子服务不支持)
- NRC 0x31 (请求超出范围)
- NRC 0x7E (活动会话中不支持子服务)
- NRC 0x7F (活动会话中不支持服务)
开始传输
- DSD 子模块应将诊断(响应)消息(肯定或否定响应)转发给 DSL 子模块,DSL 子模块将通过执行 DSL 传输功能,将诊断(响应)消息(正面或负面响应)进一步转发给 PduR 模块
- DSL 子模块在转发数据时将收到 PduR 模块的确认
- DSD 子模块通过内部函数 DspInternal_DcmConfirmation() 将确认转发给 DSP 子模块
- 在不发送诊断(响应)消息(响应抑制)的情况下,DSL 子模块不发送任何响应,在这种情况下,没有数据确认从 DSL 子模块发送到 DSD 子模块,但 DSD 子模块仍将调用内部函数 DspInternal_DcmConfirmation()
- Xxx_Confirmation() 的调用应该在 DspInternal_DcmConfirmation() 之后进行
- 如果操作 Indication() 返回 E_REQUEST_NOT_ACCEPTED,则 Dcm 模块不发送任何诊断响应,并结束当前诊断请求管理
- 如果操作 Indication()返回值 E_NOT_OK,则 Dcm 模块应发送一个 NRC 值等于 ErrorCode 参数值的否定响应