AUTOSAR DLT(Diagnostic Log and Trace)模块详解
AUTOSAR DLT 模块全面解析
技术原理
AUTOSAR DLT(Diagnostic Log and Trace)模块是 AUTOSAR 体系中用于日志记录和跟踪信息的标准化模块。它运行在 ECU 上,用于收集来自应用软件组件(SW-C)、基础软件模块(如 DET、DEM)的日志(Log)和跟踪(Trace)信息,并通过通信总线将这些信息发送到外部工具进行监视和存储。DLT 模块处于 AUTOSAR Classic 平台的软件服务层,位于 RTE 下方、PduR 之上,与诊断事件管理(DEM)和开发错误追踪(DET)等模块协同工作,但侧重点不同。通过 DLT,开发者可以实现 ECU 内各软件部分统一的日志接口、分级过滤、消息格式化和缓冲、以及与外部调试工具的通信,从而大大提升系统的可调试性和诊断能力。
DLT 协议结构
DLT 定义了一套标准化的日志/跟踪通信协议,用于封装和传输ECU中的调试信息和控制指令。DLT 消息 是传输日志和跟踪事件的基本单位,采用固定的报文格式,包括消息头和有效载荷两大部分。DLT 模块对外通过通信总线发送日志消息或接收控制消息,其协议与具体总线无关,可以在以太网、串口等多种物理介质上传输。在 AUTOSAR R21-11规范中,DLT 模块遵循标准的 Log and Trace Protocol 来进行消息封装和传输。这一协议不仅用于传输调试日志数据,也用于传输控制命令,二者使用相同的报文格式进行封装。这意味着无论是普通的日志/跟踪信息,还是外部工具发送的控制指令(比如更改日志级别),都以统一的 DLT 消息格式通过 PduR 路由到通信接口,再发送给外部 DLT 客户端或从客户端传入 ECU。DLT 协议栈的结构如下图所示:
图 1:AUTOSAR DLT 模块在ECU中的位置及与其他模块的关系(示意图)。DLT 模块位于服务层,通过 PduR 接入通信栈,与SW-Cs通过RTE接口交互,上行与DET、DEM等模块协同。外部DLT客户端通过网络或串口与ECU的DLT模块通信,实现日志的获取和控制命令下发。
如上图所示,应用层的 SW-C 调用 DLT 提供的接口发送日志/跟踪消息,DLT 模块对消息进行处理(过滤、格式化、缓冲),再通过 PduR 将消息路由到具体通信接口(如以太网的 SoAd 模块或串口接口),发送到PC上运行的 DLT Viewer 等外部客户端。反之,外部客户端发送的控制命令经由相反路径传递给 DLT 模块,由 DLT 解析并执行相应操作(如更改过滤级别),并在必要时通知相关的应用 SW-C。
DLT 消息格式
DLT 消息头由标准头(Standard Header)和可选的扩展头(Extended Header)组成,用于描述消息的元信息。标准头固定16字节,包含以下字段:
Byte0: Header Type (HTYP) – 指示消息头的选项和协议版本,包括:是否包含可选的 ECU ID、Session ID、时间戳等字段,以及协议版本号,字节序标识等。该字节的各比特含义如下:
UEH
(Use Extended Header):1 表示存在扩展头。MSBF
(Most Significant Bit First):字节序标志,1 表示大端。WEID
(With ECU ID):1 表示标准头中包含 ECU ID 字段。WSID
(With Session ID):1 表示包含 Session ID 字段。WTMS
(With Timestamp):1 表示包含时间戳字段。VER
(Protocol Version):协议版本号(4 位),当前规范版本为1。
Byte1: Message Counter – 循环计数的消息序号,0~255,发送每条消息时递增,用于检测消息丢失或乱序。
Byte2-3: Length – 消息长度,包含整个 DLT 消息(标准头+扩展头+有效载荷)的字节数。
Byte4-7: ECU ID – (可选) ECU 标识符,4字节ASCII,用于指示是哪一个ECU发送了此消息。通常配置为车辆内唯一的名称,如“ECU1”、“ADAS”等。
Byte8-11: Session ID – (可选) 会话标识,4字节值,用于区分日志/跟踪消息的来源会话。当同一应用或SW-C有多个实例时,可为每个实例指定不同的 Session ID,以在日志中加以区分。如果未使用,该字段可省略。
Byte12-15: Timestamp – (可选) 时间戳,4字节,根据配置可为相对于ECU启动的时间偏移(通常以毫秒计),用于给日志打上时间标签。DLT 可以通过Time Sync(如StbM)或GPT获取当前时间用于记录。
如果 Header Type 的 UEH
位为1,则在标准头之后会紧接扩展头,长度为10字节。扩展头包含以下信息:
Byte0: Message Info – 1字节,描述消息的类型和附加信息。其位定义如下:
VERB
位:Verbose 标志。1表示消息有效载荷包含详细(冗余)信息,0表示为Non-Verbose模式(非冗余模式)。MSTP
(Message Type):消息主类型,2位,可取4种值:- 0x0: LOG 日志消息(应用或BSW输出的调试信息);
- 0x1: TRACE 跟踪消息(通常由RTE产生的通信数据跟踪);
- 0x2: NW 网络消息(网络相关的日志,较少使用);
- 0x3: CONTROL 控制消息(外部发送的控制命令)。
MTIN
(Message Type Info):消息子类型,4位。其含义取决于主类型。例如:- 对于 LOG 类型,MTIN 指示具体日志级别(Fatal/Error/Warn/Info/Debug/Verbose)。
- 对于 CONTROL 类型,MTIN 则区分具体的控制命令种类(如设置日志级别、请求信息等,详见后述控制命令部分)。
- 对于 TRACE 类型,MTIN 可用于标识不同的跟踪类别。
- 对于 NW 类型,则表示特定的网络消息类型。
Byte1: Number of Arguments – 参数个数。仅在冗余(Verbose)模式下有意义,表示该消息的有效载荷中包含的参数数量。在非冗余模式下,该字段固定为0x00。
Byte2-5: Application ID (APID) – 应用ID,4字节ASCII,用于标识产生此消息的应用程序或SW组件。例如“APP1”“ENGN”等。APID在一个ECU内应当唯一,典型地每个SW-C配置一个固定的 Application ID。
Byte6-9: Context ID (CTID) – 上下文ID,4字节ASCII,由用户定义用于对来自同一应用的日志进行分类。每个应用ID下可以有多个Context ID,用于区分模块、子功能或任务等。例如应用 “APP1” 下可以定义CTX1="INIT", CTX2="COMM" 等。APID和CTID的组合可唯一标识日志来源。
完整的 DLT 消息头由上述标准头(16字节)和(可能存在的)扩展头(10字节)构成,总计 16 或 26 字节。有效载荷紧随消息头之后,用于承载具体的日志内容或控制指令数据。有效载荷的格式取决于Verbose或Non-Verbose模式,下文详述。
DLT 控制命令
除了传输日志和跟踪数据外,DLT 协议还定义了一系列控制消息,允许外部工具(如 DLT Viewer 或测试脚本)对 ECU 上的 DLT 模块进行配置和查询。控制消息属于上述 MSTP = 0x3 类型,其有效载荷承载特定的控制命令。DLT 模块接收到控制消息后,会执行相应动作,并可返回执行结果或反馈信息。这些控制命令包括但不限于:
Get Log Info – 获取当前 ECU 上已注册的应用和上下文列表及其日志级别等信息。外部客户端通过该命令可以查询有哪些模块在产生日志及各自的日志配置。
Set Log Level – 设置指定应用或上下文的日志输出级别阈值。例如可以将某个应用的日志级别动态提升为Debug,以便获取详细信息,或降低为Error以减少开销。支持灵活的作用范围:可针对特定应用的所有上下文、特定上下文、或通配符匹配一组上下文等。
Set Trace Status – 打开或关闭指定应用/上下文的跟踪消息输出。Trace一般用于RTE的通信跟踪,通过此命令可动态启停。
Set Default Log Level / Trace Status – 设置未单独配置的上下文所使用的全局默认日志级别或跟踪状态。这影响所有未被显式调整的日志源。
Store Configuration – 将当前的日志配置(如各模块的日志级别、过滤设置)保存到非易失存储(NVM)。需要ECU端DLT模块启用了 NvRAM 支持及配置了存储区域。此命令通常在调整完日志设置后下发,以便重启后仍保留修改。
Reset to Factory Default – 将 DLT 配置恢复为出厂默认状态。会重置日志级别、过滤器等为初始值,并可清除保存在NVM中的配置。
Set Message Filtering – 设置消息过滤规则,如根据应用ID或上下文ID屏蔽/使能日志。这比简单的日志级别更细粒度,允许按模块筛选输出。
Injection (Service Call) Commands – 针对启用了 Injection 功能的SW-C,可从外部触发SW-C内部的服务调用。此类命令形式上对应
DLT_InjectCall_<SessionId>
操作。当DLT收到这类控制消息时,会通过 RTE 调用对应 SW-C 的Injection服务接口,实现远程过程调用的效果(见后文SW-C注入部分)。
上述控制命令通常不需要ECU端开发者实现,AUTOSAR DLT模块内部已支持解析和执行。开发者需要做的是在配置上允许Rx PDU(接收通道)存在,并在SW-C配置中提供相应的服务端口以处理必要的通知或注入(例如日志级别变化通知、Injection回调等)。外部使用上,可以通过DLT Viewer自带的控制界面发送这些命令,或使用命令行工具 dlt-control
来发送(例如:dlt-control -a APP1 -c CONT1 -l 2
将应用“APP1”的Context“CONT1”日志级别设为ERROR)。通过这些控制命令,调试人员可以实时地调节ECU的日志行为,而无需重新刷写或重启程序。
日志等级
DLT 定义了标准的日志等级(Log Level)用于标识日志消息的重要程度。日志等级通常由低到高包括:Verbose、Debug、Info、Warning、Error、Fatal,以及关闭(OFF)共7个级别。各级别语义如下:
Verbose (V) – 最详细的日志级别,包含极为详尽的信息,主要用于深度调试。在正常情况下很少启用,因为信息量巨大。
Debug (D) – 调试级别,稍次于Verbose,提供开发者调试所需的细节信息。用于定位问题和验证逻辑。
Info (I) – 信息级别,提供一般运行状态信息,表示系统按预期工作。用于监控系统健康状态,无特别异常。
Warning (W) – 警告级别,指出可能存在问题的情况,但当前不影响系统功能。应当关注但无需马上采取措施。
Error (E) – 错误级别,指出发生了影响系统功能的问题,需要尽快解决。一般对应软件的错误处理路径被触发。
Fatal (F) – 致命级别,表示严重错误,可能导致系统崩溃或不可继续运行。需要立即关注和处理。
OFF – 日志关闭,不输出任何日志。
DLT 使用上述等级对每条日志消息进行标记,并通过过滤机制决定消息是否应当传输。每个日志消息在发送时,DLT 扩展头的 MTIN 字段会对应以上某个级别(如Fatal=0x1, Error=0x2, ... Verbose=0x5,在AUTOSAR标准中用05或16表示)。DLT 模块和外部工具都可基于日志级别进行过滤,例如只记录Error以上的重要信息等。典型地,在开发阶段可能启用较低级别(例如Debug)以收集详尽信息,而在量产环境将默认级别提高到Warning或Error以减少开销。通过运行时控制命令,可以动态调整某模块的日志级别阈值(Threshold),DLT 模块会相应地过滤低于阈值的日志,实现按需调节日志冗余度的能力。
时间戳与 Session 管理
**时间戳(Timestamp)**是 DLT 消息头中的可选字段,用于给日志添加时间信息,方便事后分析事件发生的顺序和时延。如果启用,则标准头Byte12-15会包含一个32位时间值。AUTOSAR DLT 模块通常通过计时器或时间同步模块获取当前时间:比如可配置使用 GPT(通用定时器)提供毫秒计时,或者集成StbM(全局时间同步基准模块)提供与全车同步的时间。时间戳一般表示自ECU开机后的相对时间(毫秒级计数)或绝对时间(若有外部时间基准)。DLT Viewer 等工具会利用时间戳对日志排序,并可显示人类可读的时间格式。有一个特殊的“Timing Packet”机制可进一步提高时间精度:外部可发送控制命令启用 timing packets,使 DLT 周期性插入时间同步消息,用于校准主机与ECU时钟偏差。
会话(Session)管理涉及 DLT 中对日志来源的识别和区分。AUTOSAR 规范定义,每一个产生 DLT 日志的实体被称为一个 Dlt User,可能是一个应用(SW-C)实例、RTE(虚拟功能总线)或其他基础软件模块。为了区分同一应用的多个实例,以及在ECU重新引导后的日志连续性,DLT 使用 Session 的概念:Session ID 是一个用来标识日志会话的数值。在 Classic Platform 中,Session ID 常用于区分同一SW-C的不同实例。例如,如果某SW-C根据ECU配置被实例化两次,那么可以给它们分配不同的Session ID(比如0x100和0x101),这样在日志中即使它们有相同的APID和CTID,也能通过Session ID加以区分。Session ID 在标准头Byte8-11(若启用)中携带,每个实例全局唯一。如果没有多实例需求,通常一个ECU内所有日志使用相同的Session ID即可。
Session 管理的另一个作用是标识一次ECU运行的生命周期。有的实现中,每次ECU重启可以改变一个Session序号,这样日志分析时可以断开不同重启之间的日志流。但AUTOSAR规范中并未强制要求这一点,一般Classic平台ECU每次启动Session ID固定。如果需要,也可以通过NVM或算法使Session ID在重启时变化,以便外部工具检测“Session Lost”事件。外部DLT客户端在接收到日志时,可以使用ECU ID + Session ID + 应用ID + 上下文ID的组合唯一定位日志来源。DLT Viewer会将Session ID一起显示,以辅助开发者识别日志来源实例。
Non-Verbose 模式原理
DLT 支持两种消息模式:冗余模式(Verbose Mode)和非冗余模式(Non-Verbose Mode)(有时也称详细模式和精简模式)。在冗余模式下,每条日志消息都会携带自描述的信息,包括消息的文本字符串、参数名称、类型、单位等元数据,使消息本身可以自我解析。而在非冗余模式下,为了减少总线负载,DLT 尽可能避免在通信中发送上述元数据,把这些静态信息留存在ECU外部的描述文件中。非冗余模式的工作原理可以概括如下:
ECU 端:发送日志消息时,仅传输变化的动态数据(例如变量的当前值),不发送静态的描述信息。为了使接收端能够知道如何解释这些数据,DLT 会在有效载荷中插入一个**消息ID(Message ID)**来标识该日志的格式。Message ID 通常是一个整数(长度可配置,典型为16或32位),在开发/配置时为每个不同的日志语句静态分配。除Message ID和参数值外,其余诸如日志文本模板、各参数的语义等均不包含在消息中。
外部客户端:需要持有一份该 ECU 的日志描述文件(通常是 FIBEX 或 AUTOSAR ARXML 文件),其中列出了ECU中所有可能的Message ID及其对应的详细信息。当客户端收到Non-Verbose模式的日志时,会读取Message ID,根据描述文件找到对应的文本模板和参数定义,然后将收到的参数值插入其中,恢复出完整的日志内容。这种恢复过程类似于使用格式化字符串和参数来重新拼装日志消息。
描述文件:通常由供应商或开发团队提供,符合 ASAM FIBEX 标准或 AUTOSAR 提取格式(Extract)。其中为每个日志消息定义一个唯一的ID及其静态信息,例如:
- 消息所属的应用和上下文(或模块)名称;
- 日志文本模板(如
"Temperature measurement: %f Kelvin"
); - 每个参数的名称、数据类型(如 uint8, float32)、含义单位(如 measurement_point 无单位,reading 单位为 Kelvin);
- 可能还有源代码位置(文件名和行号)等辅助信息。
在AUTOSAR框架下,可以将多个描述文件合并成一个针对整个ECU的描述文件,因为每个ECU内Message ID都是唯一的。Fibex 描述文件中,一条非冗余日志消息被等同于一个“帧”,Message ID 对应Fibex中Frame的ID属性,每个参数对应Signal元素。DLT 扩展头中的应用ID、上下文ID等也会映射进Frame元素用于标识来源。外部工具通过加载这个Fibex文件,便能正确解析ECU发来的Non-Verbose日志。
例如,有这样一条在ECU内的日志代码(伪代码):
DLT_LOG(APPID="ENG", CTXID="TEMP", LogLevel=INFO, "Temperature measurement: point=%d, reading=%f Kelvin", measurement_point, reading);
在非冗余模式下,ECU不会发送完整的格式化字符串
"Temperature measurement: point=%d, reading=%f Kelvin"
,而是给该日志语句分配一个Message ID(假设为0x1001),并在每次记录时仅发送:- Message ID = 0x1001
- 参数1值(measurement_point,例如=1)
- 参数2值(reading,例如=22.1)
ECU端将上述数据打包进DLT消息有效载荷并发送。外部DLT Viewer 收到后,查找描述文件中ID=0x1001的条目,得知:
Message 0x1001 对应文本模板 "Temperature measurement: point=%d, reading=%f Kelvin",
参数1名称="measurement_point" 类型=uint8(无单位),参数2名称="reading" 类型=float32(单位=Kelvin)。然后 Viewer 用收到的参数值替换模板中的占位符,最终在界面上显示完整的信息:"Temperature measurement: point=1, reading=22.1 Kelvin"。从而实现与Verbose模式相同的可读性。
Non-Verbose模式通过将静态信息“离线化”大幅减少了通信开销。在上述例子中,只传输了实际的1
和22.1
两个值,以及消息ID,相比传输完整字符串节省显著。AUTOSAR 规范指出,通过Non-Verbose模式可以最大限度降低运行时日志对带宽和CPU的占用。但相应地,开发流程需要维护好描述文件与代码的一致性:即如果代码里新增或修改了日志语句,需要同步更新描述文件,否则外部工具将无法正确解析(会看到Unknown ID或者错误解析)。为此,常用的做法是借助AUTOSAR工具链自动生成或更新描述文件(详见后文 Non-Verbose 实践部分)。总的来说,在资源受限或对通信负载敏感的场合(如量产环境),推荐使用Non-Verbose模式;而在开发调试阶段,Verbose模式因无需管理外部文件,使用上更直接,可视需要灵活切换。
工程配置(基于 Vector DaVinci 工具)
在 AUTOSAR Classic 平台中,DLT 模块作为标准服务需要在 ECU 配置中进行相应的配置。以下将结合 Vector DaVinci Configurator 等典型AUTOSAR配置工具中的选项,介绍 DLT 模块的主要配置要点,包括 DltGeneral 全局配置、日志通道、SW-C上下文、收发PDU及 PduR 路由等,并给出典型的配置片段示例。
DltGeneral 全局配置
DltGeneral
容器包含DLT模块的一些全局配置参数,用于启用/禁用特定功能或设定默认行为:
DltComLayer – 指定 DLT 模块所使用的通信抽象层。在AUTOSAR中,DLT需要通过 PduR 进行消息传输,因此这里必须配置为
PduR
。这确保了DLT模块将日志消息提交给 PduR,上层无感知具体通信总线。DltDevErrorDetect – 开发错误检测开关。设为 TRUE 时,DLT 模块内部启用 DET 机制,对不合理的API调用等进行报错。一般开发阶段打开此选项以捕捉配置或使用错误,量产可关闭节省资源。
DltVersionInfoApi – 版本信息API开关。TRUE则生成 Dlt_GetVersionInfo() 接口以提供版本信息。
DltDefaultLogLevel – 默认日志级别阈值。对于未在更细粒度配置中指定的SW-C上下文,将使用这个默认级别。典型设置为 WARNING 或 ERROR 等,确保系统默认不输出低优先级日志。
DltDefaultTraceStatus – 默认跟踪状态。用于控制未单独配置的上下文是否输出Trace(比如RTE的通信跟踪)。一般可默认关闭(FALSE)。
DltRingBufferSize – (如果实现支持)DLT内部环形缓冲区大小。DLT 模块可能使用环形缓冲存储待发送消息,此参数决定其容量。例如设置若干KB大小以暂存日志,避免突发日志丢失。
DltGeneralBufferOverflowStrategy – 缓冲区溢出策略。典型值包括 "DROP_TAIL"(新消息来时若缓冲满则丢弃新消息)或 "OVERWRITE_OLDEST"(覆盖最老的消息)等。开发者可根据应用需求选择日志溢出时是保留最新信息还是保留最初信息。
DltGeneralNvRamSupport – NVRAM支持开关。TRUE则启用从非易失存储加载/保存DLT配置的功能。这通常用于在ECU断电重启后恢复上次调整过的日志级别过滤等设置。若启用,需要配置一个NvM块供DLT使用。
DltGeneralNvRamRef – NvM块引用。当NvRAMSupport打开时,指定一个NvM Block,用于存储DLT的配置信息(比如当前各Context的log level等)。需在NvM配置中预留对应块。
DltGeneralRxDataPathSupport – RX数据路径支持。勾选则表示DLT启用接收通道功能,即允许接收来自外部的控制消息(以及Injection请求)。如果需要远程调整日志配置或使用注入功能,则须打开此开关,并配置对应的Rx PDU(见下节)。若关闭,则DLT不会处理任何外部输入的报文。
DltGeneralInjectionSupport – SW-C服务注入支持。为 TRUE 时,DLT 模块将为每个已配置的DLT Swc创建注入回调接口(Injection Callback)。这使能外部通过DLT向SW-C注入服务调用(远程过程调用)。这是全局配置,开启后所有DLT SW-C都具备该功能,无法单独针对某个SW-C开启/关闭。启用该功能需要同时启用RxDataPathSupport,因为外部注入请求也是通过控制消息下达的。
配置 DltGeneral 时,需要注意有些选项在资源有限的ECU上默认关闭以减少开销,只有在需要对应功能时才开启。例如,对于量产程序通常关闭 DevErrorDetect、VersionInfo 等。而如果计划使用 DLT的远程控制/注入能力,则必须保证 DltGeneralRxDataPathSupport 打开,否则ECU将忽略外部控制消息。
日志通道(LogChannel)配置
DLT 模块可以支持将日志输出到多个物理通道。例如一个ECU可能既有以太网接口用于高速日志输出,又希望通过另一个串口输出关键日志。因此配置上允许定义多个 Log Channel。每个 LogChannel 代表一条从 DLT 模块通往 PduR(再通往具体总线)的输出通道。
在配置工具中,LogChannel 通常作为 DLT 配置集合(DltConfigSet)下的子容器进行配置,如/DLTLogOutput/DLTLogChannel
。主要参数包括:
DltLogChannelId – 日志通道ID,用于区分不同通道。一般为一个数值或枚举名,各通道需唯一。可根据需要命名,如通道0=ETH_Logging,1=UART_Logging 等。
DltLogChannelName – 通道名称(若有此配置项)。可选的描述性名称,比如
"EthernetLog"
,主要用于配置文档可读性,实际通信中不发送。DltLogChannelBufferSize – 分配给该通道的缓冲区大小(字节)。DLT 模块对不同通道可使用独立缓冲,以暂存待发送消息。此值应根据通道带宽和日志量选择。带宽高的通道可配较大缓冲以避免丢消息。
DltLogChannelMaxMessageLength – 该通道支持的最大消息长度(字节)。超过此长度的日志消息可能会被截断或拆分传输。可根据底层协议MTU设置,比如UDP通道可设为1470字节左右,TCP通道可按需大一些。
DltLogChannelThreshold – 通道日志级别阈值。只有级别不低于此阈值的日志才会通过该通道发送。这个过滤作用于整个通道。例如可将某辅助通道的阈值设为 ERROR,使其只承载严重错误日志,而将主要通道阈值设为 INFO 承载更多信息。若不需要通道级过滤,可设为最低级别Verbose。
DltLogTraceStatusFlag – 通道跟踪使能标志。指明该通道是否传输Trace类型消息(RTE跟踪)。有的通道可能只想承载Log,不承载Trace,可通过此标志关闭Trace的转发。
DltLogChannelTrafficShapingBandwidth – 带宽整形参数。用于限制该通道的最高输出带宽(通常以字节/秒)。DLT 模块根据此限制对日志发送进行调制,比如延时发送或跳过一些日志,以确保平均带宽不超标。该功能用于避免日志流量挤占业务带宽,典型地对带宽较低或共享的总线(如CAN、串口)很有用。
需要注意,并非所有实现都支持上述全部参数。例如Traffic Shaping等高级功能可能仅在高端配置中可用。Vector MICROSAR DLT 支持上述大部分参数,而一些轻量实现可能只有基本的ID和阈值配置。
每个 LogChannel 还需要关联一个传输PDU(Tx PDU)。配置项为 DltTxPduRef,引用一个事先定义好的 PduR->下层的PDU,用于承载该通道的DLT消息。例如,通道0(EthernetLog)的 TxPduRef 可能指向 Pdu_DLT_Tx_PduRToSoAd
,而通道1(UARTLog)的TxPduRef指向 Pdu_DLT_Tx_PduRToUart
。这些 PDU 一般在通信模块(SoAd、LinIf等)或自定义CDD中定义。配置工具中在选择TxPduRef时会列出可用的PDU项供选择。设置了 TxPdu 后,配置工具通常会自动生成剩余的关联参数。
LogChannel 的数量可按需增加;如果仅需一个日志输出通道,也可以只配置一个。若配置了多个通道,DLT 默认会将每条日志根据配置的策略(比如Context Assignment或默认)决定发往哪个通道。可以通过 Assignment 项(后述)为不同的SW-C Context分配特定通道,否则使用默认通道。
SWC 上下文(DltSwc 与 DltSwcContext)配置
DLT SWC 配置部分用于声明哪些应用软件组件(SW-C)将使用DLT日志服务以及它们的标识参数。主要内容包括 SW-C 的 Session ID、是否接收通知,以及具体的 Context 列表等。
在配置工具中,通常会有 DLTSwc
容器(在 MICROSAR路径为/MICROSAR/DLT/DLTSwc
)用于每个需要使用DLT的 SW-C。每个 DLTSwc 配置代表一个SW-C,它包含:
DLTSwcSessionId – 为该 SW-C 分配的 Session ID。这是一个数值(范围通常0x00000000~0xFFFFFFFF),应在ECU内唯一。如果某SW-C有多个实例,每个实例应配置为单独的DLTSwc条目和不同Session ID。Session ID 会出现在DLT消息的标准头中(如果开启)以标识实例来源。未配置的SW-C将无法被DLT识别,其日志调用(如果有)可能会被忽略或需要运行时注册。
DLTSwcSupportLogLevelChangeNotification – 是否支持日志级别/跟踪状态更改通知。为 TRUE 时,DLT 模块在外部更改了该SW-C的日志级别阈值或Trace开关时,会通过RTE向SW-C发送通知回调(LogLevelChangedNotification和TraceStatusChangedNotification)。SW-C 可以实现这些回调,以在应用内采取相应动作(例如调整本地日志过滤)。如果此开关为 FALSE,则DLT不会通知SW-C,相当于静默更改。一般如果SW-C内部还需要根据日志级别采取逻辑(如减少某些计算),可开启通知。
DLTSwcName(如果有) – SW-C名称,可选配置,便于识别。
DLTSwcContexts – (重点) 一个SW-C下可预配置多个上下文(Context)。每个Context由Application ID和Context ID组成。配置工具中通常允许在一个DLTSwc下添加多个DLTSwcContext子项,对应代码中不同的日志分类。对于每个Context需设置:
- DLTSwcApplicationId – 应用程序ID,4字符标识符。可以使用SW-C名称缩写或功能名称等。一个SW-C理论上只能有一个Application ID(若配置多个Context也都共享这个App ID)。不同SW-C不要使用相同的App ID,以免混淆。
- DLTSwcContextId – 上下文ID,4字符标识符。用于区分该SW-C中不同类别的日志。例如一个SW-C可以配置Context ID "INIT"用于初始化相关日志,"COMM"用于通信相关日志等等。Context ID 需在其所属App ID范围内唯一。
配置了的上下文将自动注册到DLT模块中。这意味着在运行时SW-C不需要再调用 DLT_RegisterContext 手动注册,DLT初始化时会根据配置把这些AppID+Context对加入内部列表。如果SW-C的Context未预先配置,那么在代码中需要通过Dlt_RegisterContext注册,或者该SW-C的日志将无法正确输出(DLT会因为不识别Context而拒绝日志发送)。因此,建议把预计会使用的日志Context都在配置中列出。
需要注意约束:同一个Application ID不能分配给多个不同的SW-C Context。换言之,一个AppID应唯一定义一个SW-C(当然该SW-C可以有多个Context)。配置工具一般会确保不发生冲突。如果两个SW-C意外用了同一AppID,会导致日志归属混乱,这是不允许的。
除了上下文本身,还可以对每个已配置的SW-C Context设置特定的初始参数,包括:
DLTLogLevelThreshold – 分配给该Context的日志等级阈值。它会覆盖全局默认阈值。比如可以设某Context的初始阈值为DEBUG而其他为INFO,以便更详细跟踪特定模块。
DLTTraceStatusAssignment – 分配给该Context的Trace开关初始值。TRUE开启,FALSE关闭,覆盖全局默认Trace状态。
DLTLogChannelAssignment – 分配该Context使用的日志通道。引用某个LogChannel ID。如果未指定,默认使用 DLTDefaultLogChannelRef 所指的通道。
如果没有对某个Context显式指定以上参数,则会使用对应的全局默认值:DLTDefaultLogLevel
、DLTDefaultTraceStatus
、DLTDefaultLogChannelRef
。每个Context只能指定一个阈值和一个Trace状态(不能多通道输出同一条日志,但可以通过复制日志调用来实现在两个通道分别输出)。
通过上述SW-C和Context配置,DLT 模块在初始化时就知晓 ECU 内有哪些日志来源(APID/CTID组合),各自的初始过滤级别和输出目的,从而做好数据结构准备。这能避免运行时注册的开销,并确保日志从系统启动开始就能够被记录(如必要的话,应用的软件初始化过程中的日志也能输出)。
Rx PDU 和 Tx PDU 配置
Tx PDU 已在 LogChannel 部分提及,每个日志通道必须配置一个Tx Pdu用于发送日志数据。Tx PDU 一般在相关通信模块下预先定义。例如使用以太网传输DLT,可在 SoAd(Socket Adaptor)模块下定义一个提供给DLT的Tx PDU,类型通常是一些Transport Protocol PDU(因为DLT消息可能大于单帧,需要TP支持)。该 PDU 在PduR中作为目标(Dest PDU)使用。配置工具中选定TxPduRef后,会自动在 PduR 配置中生成相应的路由条目(或需手工配置,见下节)。
Rx PDU 则在启用了 DltGeneralRxDataPathSupport 时才需要配置。Rx PDU 用于接收来自外部的 DLT 控制消息(以及注入请求)。典型配置是在 PduR中定义一个从下层(如SoAd)到上层DLT的 PDU 路径。我们需要:
- 在通信接口模块(如SoAd)下定义一个对应的Rx PDU。比如SoAd为DLT设置了TCP服务器端口用于监听,则收到的数据通过SoAd上报到其Rx Pdu(如
Pdu_DLT_Rx_SoAdToPduR
)。 - 在DLT模块配置中,设置 DLTRxPduRef 指向上述 Pdu。有的工具这个Ref可能在 DLTConfigSet 或 DLTGeneral 下提供选项。选好后,该Rx Pdu即建立了下层->DLT的通路。
- 需确保Rx PDU长度足够容纳最大可能的控制消息长度。控制消息通常不长,但如果支持Injection,负载可能较大,要适当设置。
配置示例:Vector DaVinci 中,当在 DLTGeneral 打开RxDataPathSupport后,会出现 DLTRxPdu
项,可选择一个Pdu。选定后,会生成PduR Routing Path(Rx方向)的配置,使这个PDU从SoAd一路路由到DLT。
PduR 路由配置
PduR(协议数据单元路由器)负责在上下层模块间转发PDUs。配置DLT时,需要在 PduR 中添加相应的路由路径,以连接 DLT 模块和具体通信接口(以太网、UART等)。一般包括两条路径:
Tx 路径:DLT -> PduR -> 下层通信。作为源模块的是DLT,目标模块是比如SoAd。配置步骤:
- 在 PduR 的 RoutingTable 下新建一个
PduRRoutingPath
。可以命名为 "DltTxPath" 等。 - Source PDU:配置
PduRSrcPdu
,其引用(PduRSrcPduRef)指向来自 DLT 模块的 PDU。通常这个PDU名称形如Pdu_DLT_Tx_DLTToPduR
,是工具自动生成的DLT输出PDU标识符。选择该项。 - Destination PDU:配置
PduRDestPdu
,其引用(PduRDestPduRef)指向下层(如SoAd)的PDU。例如Pdu_DLT_Tx_PduRToSoAd
。选定后,其他如目标模块、传输协议等参数通常工具会自动填充。 - 指定该RoutingPath使用的上层模块是 DLT、下层模块是SoAd的Tx方向TP接口。Vector工具中需在 PduRBswModules 下添加 DLT 模块,以及确保 PduRTransportProtocol 列表中包含SoAd。这些通常在对DLT模块建路由时已隐含完成。
- 在 PduR 的 RoutingTable 下新建一个
Rx 路径:下层 -> PduR -> DLT,用于控制消息等进入ECU:
- 新建
PduRRoutingPath
,命名 "DltRxPath" 等。 - Source PDU:
PduRSrcPduRef
指向下层接收到的 PDU。如 SoAd 接收DLT控制数据的 PDUPdu_DLT_Rx_SoAdToPduR
。 - Destination PDU:
PduRDestPduRef
指向 DLT 模块的接收 PDU。如Pdu_DLT_Rx_PduRToDLT
。配置后工具会将目标上层模块标识为 DLT。 - 相应地,需确保 PduR 中已包含 SoAd 作为传输协议模块,以及 DLT 作为上层模块(与Tx路径配置相似,不再重复)。
- 新建
配置完成后,PduR 在运行时会据此将 DLT 模块送出的消息递交给 SoAd 发出,以及将 SoAd收到的数据交给 DLT 模块处理。以上配置在DaVinci Configurator中多数可由向导或拖拽选择自动生成,只需仔细选择正确的PDU引用,保持名称一致。值得一提的是,Vector 工具要求用户拥有 PduR 对应总线类型(如以太网TP)的license才能生成相关代码。
典型配置片段示例
下面给出一个简化的 DLT 模块 ARXML 配置示例,展示上述配置项在 ECU 配置描述中的样子(非真实语法,仅为说明):
<!-- DLT 全局配置 -->
<ECUC-CONTAINER-VALUE SHORT-NAME="DltGeneral">
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltComLayer" VALUE="PduR"/>
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltDefaultLogLevel" VALUE="3"/><!-- WARNING -->
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltDefaultTraceStatus" VALUE="0"/><!-- OFF -->
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltGeneralRxDataPathSupport" VALUE="true"/>
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltGeneralNvRAMSupport" VALUE="true"/>
<ECUC-REFERENCE-VALUE DEFINITION="DltGeneralNvRamRef" VALUE-REF="NvMBlockDescriptor/DLT_ConfigBlock"/>
</ECUC-CONTAINER-VALUE>
<!-- DLT 配置集合 -->
<ECUC-CONTAINER-VALUE SHORT-NAME="DltConfigSet">
<!-- 日志通道配置: 通道0 - Ethernet -->
<ECUC-CONTAINER-VALUE SHORT-NAME="DltLogChannel">
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltLogChannelId" VALUE="0"/>
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltLogChannelBufferSize" VALUE="4096"/><!-- 4KB -->
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltLogChannelThreshold" VALUE="4"/><!-- INFO -->
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltLogTraceStatusFlag" VALUE="1"/><!-- enable trace -->
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltLogChannelTrafficShapingBandwidth" VALUE="1000000"/><!-- 1MB/s -->
<ECUC-REFERENCE-VALUE DEFINITION="DltTxPduRef" VALUE-REF="Com/Pdu_DLT_Tx_PduRToSoAd"/>
</ECUC-CONTAINER-VALUE>
<!-- 可选: 默认通道引用,如果多个通道 -->
<ECUC-REFERENCE-VALUE DEFINITION="DltDefaultLogChannelRef" VALUE-REF="DltConfigSet/DltLogChannel/0"/>
<!-- Rx PDU 引用 -->
<ECUC-REFERENCE-VALUE DEFINITION="DltRxPduRef" VALUE-REF="Com/Pdu_DLT_Rx_SoAdToPduR"/>
</ECUC-CONTAINER-VALUE>
<!-- DLT SW-C 配置: 例如一个名为 "CtDemo" 的 SW-C -->
<ECUC-CONTAINER-VALUE SHORT-NAME="DltSwc_CtDemo">
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltSwcSessionId" VALUE="4096"/>
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltSwcSupportLogLevelChangeNotification" VALUE="true"/>
<!-- Context 列表 -->
<ECUC-CONTAINER-VALUE SHORT-NAME="DltSwcContext">
<ECUC-TEXTUAL-PARAM-VALUE DEFINITION="DltSwcApplicationId" VALUE="DEMO"/>
<ECUC-TEXTUAL-PARAM-VALUE DEFINITION="DltSwcContextId" VALUE="INIT"/>
</ECUC-CONTAINER-VALUE>
<ECUC-CONTAINER-VALUE SHORT-NAME="DltSwcContext">
<ECUC-TEXTUAL-PARAM-VALUE DEFINITION="DltSwcApplicationId" VALUE="DEMO"/>
<ECUC-TEXTUAL-PARAM-VALUE DEFINITION="DltSwcContextId" VALUE="COMM"/>
</ECUC-CONTAINER-VALUE>
<!-- 为Context指定特定通道或级别 (可选) -->
<ECUC-CONTAINER-VALUE SHORT-NAME="DltLogLevelSetting">
<ECUC-NUMERICAL-PARAM-VALUE DEFINITION="DltLogLevelThreshold" VALUE="5"/><!-- DEBUG for this SWC -->
</ECUC-CONTAINER-VALUE>
<ECUC-CONTAINER-VALUE SHORT-NAME="DltLogOutput">
<ECUC-REFERENCE-VALUE DEFINITION="DltLogChannelAssignment" VALUE-REF="DltConfigSet/DltLogChannel/0"/>
</ECUC-CONTAINER-VALUE>
<!-- TraceStatusSetting similarly if needed -->
</ECUC-CONTAINER-VALUE>
上述片段展示了一个具有1个日志通道和1个SW-C的简单配置。通道0使用以太网SoAd发送,SW-C CtDemo
分配了Session 4096,ApplicationID "DEMO",有两个Context "INIT"和"COMM",并启用了日志级别变化通知。其默认日志级别设为DEBUG(5),使用通道0输出。RxPdu配置使能了外部控制。实际ARXML会更复杂,包括模块定义引用等,这里仅突出关键结构供参考。
SWC 集成与应用案例
配置完成DLT模块后,需要在应用软件组件(SW-C)中集成使用 DLT 提供的日志服务接口,并在代码中适当调用这些接口输出日志或跟踪信息。本节通过实际应用案例,说明 SW-C 如何发送日志/Trace,如何使用DLT提供的宏/API,以及如何处理日志级别的动态调整等问题,并给出示例代码片段。
日志消息发送
Classic AUTOSAR中,SW-C 访问 DLT 服务通常通过 RTE 提供的服务端口。在SW-C的组成结构中,可以添加一个提供(Provides)的客户端/服务器端口,绑定到AUTOSAR标准的 DLT 服务接口。例如 Vector DaVinci Developer 工具有内置的 DLT Port Interfaces:DLTSwcMessageService
即为发送日志/跟踪的服务接口,SW-C通过实现该接口(作为Required端口的服务器端)即可使用 DLT 的发送功能。这个接口定义了以下主要操作:
DLT_RegisterContext
– (可选)注册一个新的应用ID和Context ID。对已静态配置的Context通常不需要调用。对未配置的Context,如果要使用日志,需在运行时调用此操作通知DLT模块。调用成功后DLT模块会将该Context纳入管理,并可通知外部工具新的Context出现。DLT_SendLogMessage
– 发送一条日志消息。参数通常包括:日志级别、应用ID/Context(如果事先注册过Context则可仅传句柄)、以及日志Payload(例如格式化字符串和可变参数)。调用此操作会将日志提交给DLT模块,DLT模块进一步处理并通过PduR发送出去。DLT_SendTraceMessage
– 发送一条跟踪消息。含义类似上面,只是标记为Trace类型(MSTP=Trace)。通常由RTE隐式调用产生,但应用层也可主动调用以发送跟踪信息。
在SW-C内部,使用上述接口输出日志的典型流程是:初始化阶段(如Init Runnable)注册Context(若需要)并激活DLT,然后在运行阶段适当位置调用 SendLogMessage/SendTraceMessage 输出信息。例如:
/* 假设SW-C通过RTE有一个名为 LogIf 的Server Port,类型为 DLTSwcMessageService */
#include "Rte_DemoSwc.h" // RTE header providing Rte_Call functions
Std_ReturnType DemoSwc_Init(void) {
// 激活 DLT 模块(若DLT默认未激活,需要调用SetState)
Rte_Call_LogIf_DLTSetState(DLT_ON); // DLT_ON 通常=1
// 注册上下文(若Context未静态配置,则需要)
Rte_Call_LogIf_RegisterContext("DEMO", "RUN", &contextHandle);
return RTE_E_OK;
}
void DemoSwc_Cyclic(void) {
static uint16 count = 0;
// 读取某传感器数据
float32 reading = GetSensorReading();
// 发送日志消息 (等级: INFO)
Rte_Call_LogIf_SendLogMessage(DLT_LOG_INFO, "Sensor reading #%d: %.2f", count++, reading);
// Optionally: 发送Trace消息举例
// Rte_Call_LogIf_SendTraceMessage("Value updated", lastValue, newValue);
}
*示例代码:*上例展示了SW-C初始化时通过RTE接口激活DLT、注册Context,以及在周期任务中发送日志的逻辑。Rte_Call_LogIf_SendLogMessage
由RTE生成,内部会调用DLT模块的同名函数,将日志文本和参数传递给DLT模块处理。DLT随后将其封装并通过PduR发送到外部。
需要注意以下事项:
DLT 激活:某些实现中,DLT 模块在初始化后默认为非活动状态,以减少不必要的运行时开销(因为禁用状态下不上报日志)。此时必须先调用
DLT_SetState
(通过端口DLTStateHandling
提供)将 DLT 激活。Vector 配置中,建议在SW-C的 Init Runnable 中调用一次DLT_SetState(ON)
。激活后DLT才会真正处理后续日志消息;否则SW-C调用SendLogMessage可能无效。Context 注册:如果SW-C的Application ID和Context ID已经在配置中静态配置(即DLTSwc/DLTSwcContext已经存在),那么 不需要 在运行时调用 RegisterContext。DLT模块已知这些Context,可直接接受日志消息。但对于那些未静态配置的(比如动态创建的模块、或为了节省配置省略的Context),则在第一次使用前必须调用注册,否则DLT会拒绝处理(可能返回错误)。一般建议尽量在配置阶段枚举所有会用到的Context,从而避免RegisterContext步骤。
日志发送:SendLogMessage/SendTraceMessage 的实现,通常会立即返回Std_ReturnType,表示消息是否成功排入发送队列。并不保证消息立刻发送完成,只表示交由DLT模块成功与否。失败的情况可能是DLT未激活、对应Context未注册、缓冲已满等。应用可根据返回值决定是否重试或报错。
宏封装:为了简化调用,一些DLT库或RTE会提供宏。例如有的实现定义
DLT_LOG(hnd, lvl, fmt, ... )
宏,用于在本地调用时自动填入Context handle、文件名/行号等信息,再调用SendLogMessage。也有宏DLT_TRACE()
类似。使用宏的好处是代码简洁,并可在Verbose模式下携带源码位置信息。开发者可根据具体平台文档使用相应的宏接口。
Trace 跟踪消息输出
Trace消息用于记录AUTOSAR虚拟功能总线(VFB)上的数据流或SW-C内部的函数/状态流转情况。其不同于普通Log的地方在于:Trace更关注“跟踪事件”,例如RTE通过特殊钩子在发送/接收各Runnable时调用 DLT 输出trace。SW-C 可以通过调用 SendTraceMessage
来输出自定义trace信息,例如进入某函数、某数据更新等。Trace的等级本质上只有开/关(Trace Status),在DLT扩展头用一个bit表示。
启用Trace输出需要在配置中打开相应开关。DLT对每个Context维护一个Trace Status(On/Off),默认由DltDefaultTraceStatus给定。SW-C 可以在运行中通过 DLT_SetTraceStatus
控制某Context的Trace开关(通常由外部工具触发)。当Trace关闭时,SW-C 即使调用SendTraceMessage,DLT 也会过滤掉不发送。Trace的使用案例包括:
RTE VFB Trace:AUTOSAR RTE可配置与DLT联动,自动在每次发送/接收COM信号、Runnable启动结束等事件上调用DLT宏输出trace,从而在日志中重现软件系统的执行序列。开发者在DLT Viewer上即可看到诸如“ComponentA -> ComponentB signal X updated”等跟踪信息,便于分析复杂的SW间交互。此功能需RTE生成代码支持,在配置中RTE通常提供勾选,使能 VFB Trace to DLT 的选项。
应用自定义Trace:SW-C 开发者也可用Trace作为一种分级日志。例如Log主要记录结果变化,而Trace记录详细流程。当需要深入调试时打开Trace获取更多细节。通过配置独立的Trace开关,可单独控制,而不影响正常Log。使用方法与Log类似,只是调用SendTraceMessage,且消息在DLT Viewer中会被标记为Trace类型(通常不同颜色或图标)。
Trace消息在DLT Viewer中和普通日志一起呈现,但可以通过过滤(按MSTP类型)将Trace单独筛选。由于Trace可能产生大量数据,建议仅在需要时开启。另外Trace消息格式通常比较简单,不像Log有明确等级分类,使用时可以在文本里注明事件性质以便阅读。
DLT 宏和API的使用
为了方便工程师使用DLT,一些常用功能封装成了宏和辅助API:
可变参数格式化:DLT SendLogMessage接口往往允许像printf那样带格式字符串和可变参数。内部DLT实现会根据Verbose或Non-Verbose模式处理这些参数:在Verbose模式下,将格式化后的完整字符串发送;在Non-Verbose模式下,则提取参数列表,生成MessageID并发送参数值。开发者使用时只需像使用printf一样调用接口,DLT模块会负责完成底层格式化或打包。例如上例中的
"Sensor reading #%d: %.2f"
会在ECU格式化为 "Sensor reading #5: 27.30" 发送(Verbose),或在Non-Verbose下发送ID和两个参数值(5和27.30)。文件名和行号:DLT 支持可选地记录日志的源代码文件和行号。在配置 DltProtocol 时可以选择 WSFLN (With Source File and Line Number) 选项,这样Verbose模式下DLT消息的Payload里会附加文件名:行号信息;Non-Verbose模式下这些静态信息也可写入描述文件。许多DLT库提供宏例如
DLT_LOG_VERBOSE(context, "message", ...)
,内部展开时利用__FILE__
和__LINE__
将信息传递给DLT。外部工具可以显示或过滤特定文件的日志,大大方便调试定位。断言与错误报告:DLT 可作为断言失败或错误上报的管道。例如DET模块报告一个开发错误时,可以调用DLT输出一条Fatal级日志。一些项目中会封装宏
DLT_ASSERT(condition)
,在condition不满足时通过DLT输出断言失败信息并(可选)触发系统复位或安全状态。这提供了比标准DET更丰富的信息输出手段。性能日志:DLT除了普通日志,也可以用来记录性能指标,如时间测量结果等。开发者可以用特定Context(比如 "PERF")输出关键函数耗时、内存使用等调优信息。在外部工具通过Trace或日志分析,可以可视化性能数据,对系统优化有帮助。
总之,DLT提供的API/Macro使日志记录灵活而强大。开发者应根据项目需要选用合适的接口:RTE封装的调用方便AUTOSAR组件集成,而直接C函数或宏在一些非AUTOSAR部分(如在Complex Device Driver代码中)也可使用。需要确保的是,不管哪种方式,都应遵循前述配置:Context必须已注册、DLT已激活,并考虑Non-Verbose模式下描述文件同步更新等。
日志级别动态调整
在系统运行过程中,出于调试或诊断需要,工程师可能希望动态地调整某些模块的日志详略程度。借助DLT的控制命令和通知机制,可以实现这一目标。
当外部使用DLT Viewer或dlt-control
发送“SetLogLevel”命令时,DLT模块会修改指定 Application/Context 的日志级别阈值,并立即生效。例如,某组件平时日志级别是WARNING,通过一条控制消息可以提升其级别到DEBUG,从而开始输出大量调试信息。这个改变发生在运行中,不需要重启ECU。
为了让SW-C本身知晓这种更改(有时SW-C内部也需根据日志级别做一些处理,比如减少某些详细计算),DLT 提供了日志级别变化通知(LogLevelChangedNotification)和Trace状态变化通知(TraceStatusChangedNotification)。如前述SW-C配置中打开了SupportLogLevelChangeNotification,则DLT模块在更改该SW-C的过滤设置后,会调用该SW-C通过RTE提供的LogTraceSessionControl
接口的通知操作。SW-C 需要实现这些通知操作,比如:
// SW-C 提供的接口 Operation 实现
void LogLevelChangedNotification(AppId app, CtxId ctx, uint8 newLevel) {
// 记录新的日志级别,应用内据此可调整行为
currentLogLevel = newLevel;
if(newLevel < DLT_LOG_DEBUG) {
DisableDetailedCalc(); // 关闭一些详尽但耗时的计算,减少干扰
} else {
EnableDetailedCalc();
}
}
上例展示,当日志级别降到INFO以上时,SW-C内部关闭详细计算逻辑,以降低CPU负载;当调到DEBUG时又打开。类似地TraceStatusChangedNotification可让SW-C知道trace是否开启。
需要注意,如果SW-C不关心这些变化,可以不启用通知,这样DLT改阈值时SW-C无感知。然而DLT模块本身会始终依据新阈值过滤日志输出。也就是说,即便SW-C不了解,实际上低于新阈值的日志已经被丢弃,不再发送。最佳实践是让SW-C也尽量遵守当前级别,以减少不必要的 SendLogMessage
调用(因为那些最终会被过滤掉)。这可以通过通知回调或SW-C定期查询当前级别(DLT也提供 GetLogLevel 接口供SW-C查询)来实现。
总的来说,借助DLT的动态级别控制,车辆在现场出现问题时,可以远程将相关模块的日志打开到DEBUG收集详尽信息,问题分析完毕后再调回INFO以免影响性能,极大提升了调试和运维效率。
示例:综合案例代码
下面给出一个综合示例代码片段,展示SW-C与DLT交互的各方面要点,包括激活DLT、注册上下文、发送日志/trace、处理通知以及使用宏等:
#include "Rte_MySwc.h" // 假设SW-C名称为MySwc
#include "Dlt.h" // 假设直接包含了底层DLT库头(包含宏定义等)
// 假设配置中已定义 ApplicationID="MYSW", ContextID="MAIN"
#define APPID "MYSW"
#define CTXID_MAIN "MAIN"
static DltContext myContext; // DLT上下文句柄(结构体)
// 初始化函数
Std_ReturnType MySwc_Init(void) {
// 1. 激活DLT模块(如果需要)
Rte_Call_DLTStateHandling_SetState(DLT_ON);
// 2. 注册Context(若未静态配置,则需要)
DLT_REGISTER_CONTEXT(&myContext, APPID, CTXID_MAIN, DLT_LOG_INFO);
// 上面假设DLT库提供宏,将调用 Dlt_RegisterContext()
return RTE_E_OK;
}
// 周期运行函数
void MySwc_Run(void) {
uint32 rpm = GetEngineRPM();
float32 temp = ReadCoolantTemp();
// 3. 发送信息日志
DLT_LOG(myContext, DLT_LOG_INFO, "Engine RPM=%u, Coolant=%.1f C", rpm, temp);
// 4. 发送Trace跟踪(假设用于跟踪重要变量变化)
static uint32 lastRpm = 0;
if(rpm != lastRpm) {
DLT_TRACE(myContext, "RPM changed: %u -> %u", lastRpm, rpm);
lastRpm = rpm;
}
// 5. 某错误情况,发送错误日志
if(temp > OVERHEAT_THRESHOLD) {
DLT_LOG(myContext, DLT_LOG_ERROR, "Overheat! Temp=%.1f C", temp);
// 也可调用DEM上报DTC,然后DLT内部亦可记录
}
}
// 日志级别变化通知(通过RTE提供)
void MySwc_LogLevelChanged(uint8 newLevel) {
// 根据新级别调整内部行为
if(newLevel < DLT_LOG_DEBUG) {
VerboseMode = FALSE;
} else {
VerboseMode = TRUE;
}
}
上述代码中:
使用了假定存在的
DLT_REGISTER_CONTEXT
,DLT_LOG
,DLT_TRACE
宏,简化了调用书写。这些宏内部会利用myContext
句柄(其中包含AppID/CtxID等信息)调用 Dlt库函数。需确保在MySwc_Init
中已正确注册context。在
MySwc_Run
中,根据当前Engine RPM和温度发送Info日志,每当RPM变化时发送Trace以跟踪变化过程,当温度超标时发送Error日志警示。MySwc_LogLevelChanged
则作为RTE通知,实现当外部调节了此SW-C日志级别时,SW-C将VerboseMode标志调整,用于控制额外详细日志的输出。
这个综合示例体现了 DLT 集成的各关键环节。在实际项目中,开发者应根据AUTOSAR方法,通过RTE调接口或直接调用Dlt库接口来实现类似逻辑,并充分测试在不同配置(Verbose vs Non-Verbose、不同初始级别、外部控制调节等)下日志行为是否符合预期。
服务注入(Injection)功能
DLT 还有一个高级功能称为服务注入(Service Injection)。它允许外部通过DLT渠道请求ECU内的SW-C执行特定的操作(类似远程过程调用)。这对于远程测试和故障定位非常有用,例如可以请求某SW-C调用其内部的一个调试接口来采集额外数据。AUTOSAR DLT 通过在SW-C和DLT之间建立一套 Injection 通信接口 实现该功能。
要使用Injection功能,需要在配置中:
全局启用 DltGeneralInjectionSupport(如前述),并启用 RxDataPathSupport。
在相关SW-C上,增加 DLTInjection 和 InjectionCallback 两个服务端口:
- DLTInjection(Client-Server接口):SW-C 通过Required端口调用,用于主动向其他SW-C注入服务。但更常用的是由DLT Master调用,因此SW-C本身可能不用此端口。
- InjectionCallback(Client-Server接口):SW-C 提供,用于接收DLT模块转发的注入请求调用。DLT模块会为配置的每个Session创建一个Operation,例如
DLT_InjectCall_4096
,当外部发送针对Session 4096的注入指令时,DLT模块就调用对应SW-C的InjectionCallback端口。
SW-C 实现 InjectionCallback 的
InjectCall
操作。这个操作通常定义为一个通用接口,参数可能是服务ID和输入数据,由SW-C据此决定执行什么服务。例如一个SW-C里面实现了若干测试函数,每个赋予一个ID,InjectCall收到ID后用switch-case调用相应函数,并返回执行结果(可能通过DLT响应消息)。
当上述配置和实现完成后,使用过程为:
外部人员在DLT Viewer上构造并发送一个控制命令,比如 “Inject Call: SW-C Demo, Session 4096, ServiceID=5, Payload=[...data...]”。DLT Viewer将此封装为DLT Control报文(MTIN类型Injection)发送到ECU。DLT 模块收到后,识别出Session 4096,查找对应SW-C的InjectionCallback端口,调用其 InjectCall
实现,并将ServiceID和参数传过去。SW-C 执行相应服务(比如读取某传感器详细状态),然后可以通过DLT再发送一个响应消息(可能也是预定义Message ID),Viewer上即可显示结果。
值得注意的是,Injection功能需要谨慎使用。因为它事实上允许外部在运行中的ECU上执行任意定义好的函数,这对安全和系统完整性有影响。因此应确保只有开发调试模式下才启用,且注入的服务集是有限且经过验证的。通常在量产代码中会关闭Injection支持以防滥用。
Injection 功能展示了 DLT 的另一强大之处:不仅仅是日志输出,它还可以成为双向通信接口,使外部工具与ECU内部逻辑互动。对于复杂问题的现场诊断,它提供了一条无须重新编译刷写的新途径。
串口输出实现
虽然以太网带宽高且便于使用DLT Viewer,但在某些ECU上可能没有以太网接口或测试环境无法使用网络。这时,可以考虑通过**串口(UART)**来输出DLT日志。下面介绍如何将DLT路由到UART,以及PC端如何接收串口日志并与DLT工具对接的方法。
DLT 路由到 UART 的方案
AUTOSAR 标准并没有现成的 "UARTIf" 模块用于日志输出,但我们可以利用 PduR 的灵活性,结合微控制器的串口驱动,搭建一条UART通道。基本思路是:将UART看作一种传输链路,实现类似SoAd的适配模块,使DLT消息通过PduR发送到UART硬件。
可能的实现途径:
模拟TP协议发送:DLT消息长度可能超过常规帧,需要考虑分段。幸运的是UART是字节流,不存在固定帧长。因此可以简单地将整个DLT消息作为一帧发送。为此,可以仿造一个简易的Transport Protocol:即定义UART每次发送的数据块起始包含DLT标准头的同步字节序列,以便接收端知道一条消息的边界(GENIVI DLT daemon在串口模式下采用了一个特殊的Serial Header用于同步)。在AUTOSAR层面,可以直接发送DLT消息本身,因为标准头包含长度字段,接收方可以据此确定消息边界,从而在流式UART中拆分出每条消息。
自定义UART接口模块:实现一个类似SoAd的模块(可作为Complex Device Driver):
- 提供向下调用UART驱动发送数据的函数,如
UartIf_Transmit(PduId, *Data, Len)
。 - 提供接收中断回调,将UART接收的数据组装成Pdu后上报PduR。
- 由于UART通常速度较低且使用可靠性不如TCP,这里可以假设不支持复杂的流控,就尽最大努力发送即可。
- 提供向下调用UART驱动发送数据的函数,如
PduR配置:将此自定义UART接口注册到PduR的BswModules,类似之前SoAd的配置:
- 增加一个 PduR BswModule 条目,比如
UARTIF
,上层模块指向DLT,下层就是UART驱动。 - 配置一个Tx Routing Path:Src PDU =
Pdu_DLT_Tx_DLTToPduR
,Dest PDU =Pdu_DLT_Tx_PduRToUART
。目标模块选择 UARTIf。 - 配置一个Rx Routing Path(如果需要接收控制):Src PDU =
Pdu_DLT_Rx_UARTToPduR
,Dest PDU =Pdu_DLT_Rx_PduRToDLT
。源模块UARTIf,目标模块DLT。 - 这样,DLT模块的输出会通过PduR调用到 UartIf 的 Transmit 函数,将数据写入UART;反之外部发送的数据经UARTIf上报给DLT。
- 增加一个 PduR BswModule 条目,比如
串口硬件配置:设置波特率(115200等)、数据位、校验等与PC端一致。DLT Daemon默认波特率115200,可配置。
需要注意串口传输的局限:115200bps 大约每秒只能传输11KB数据,远低于以太网。大量Verbose日志可能会导致丢失。因此在UART通道通常只输出关键信息或使用Non-Verbose模式压缩数据。此外,UART没有内置重传机制,干扰可能造成数据损坏,所以一般用于实验/开发环境,不用于关键日志。
PduR 与 UartIf 的接口设计
设计UartIf模块时,可以参考Com和LinIf的做法:
Transmit接口:实现
UartIf_Transmit(PduId, *PduInfo)
。内部调用MCU提供的UART发送API,将PduInfo里的数据发出。如果UART驱动有发送缓冲,可异步处理;否则需同步等待发送完成(通常UART带FIFO,可以异步)。Receive处理:UART驱动在收到数据时中断通知UartIf。UartIf可以每接收一个字节就放到一个缓冲,并尝试解析DLT报文完整性。如果实现复杂,可以简单地每收到N字节就上报一次Pdu给DLT,因为DLT daemon在串口模式下提供了同步选项
RS232SyncSerialHeader
来对齐消息。Serial Header:GENIVI DLT设计中,为串口传输定义了一个2字节的特殊头0x44 0x4C(ASCII 'DL')用于帧同步和校验。不过如果双方约定DLT消息连续发送且使用Length字段判断,也可以不使用额外Header。配置文件
dlt.conf
里RS232SyncSerialHeader=1
表示启用同步头。工程上可选择实现与dlt-viewer匹配的方案。简单起见,可以不添加额外头,让PC端工具以“无同步头模式”读取。
Vector MICROSAR 本身并未提供UARTIf,开发者需要自己实现CDD。但配置思路与SoAd类似。一些开源方案可能复用了LinIf或CanIf来发送串口数据,但那会引入额外协议,不如直接CDD简单。
PC 端桥接脚本
ECU通过串口输出DLT日志后,需要在PC端接收并呈现。这可以通过两种方式:
1. DLT Viewer 直接串口连接:GENIVI DLT Viewer支持通过串口连接DLT Daemon。在其菜单中可以选择串口模式并配置串口名和波特率。前提是在ECU侧运行有DLT Daemon监听串口。但在Classic ECU(无操作系统)情况下,没有独立的DLT Daemon进程,此法不可行。另外,PC直连串口通常需要转换器和专用线缆,Viewer配置稍麻烦。因此更常用第二种方式。
2. 桥接TCP通道:在PC上运行一个小程序,充当“串口<->TCP桥”。它一端打开ECU串口,读写数据;另一端开启一个本地TCP端口,等待DLT Viewer连接。DLT Viewer本身仍以TCP模式运行,只是目标IP是本地(127.0.0.1),端口比如3490,而桥接程序把来自Viewer的数据发到串口,串口收到的数据转发给Viewer。这种方式的优点是使用了Viewer成熟的TCP逻辑,并可在需要时加上缓冲或重传策略。
一个简单的Python桥接脚本示意:
import serial, socket
# 打开串口
ser = serial.Serial('COM3', baudrate=115200, timeout=0)
# 建立TCP服务器
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.bind(('127.0.0.1', 3490)); srv.listen(1)
client, addr = srv.accept()
# 进入转发循环
while True:
# 串口->TCP
data = ser.read(1024)
if data:
client.sendall(data)
# TCP->串口
try:
net_data = client.recv(1024)
if net_data:
ser.write(net_data)
except BlockingIOError:
pass
将上述脚本运行在PC,然后在DLT Viewer里添加一个TCP连接,指向127.0.0.1:3490
。这样,Viewer发送的控制命令经由脚本到达串口ECU,ECU日志通过串口到脚本再送入Viewer。整个流程对Viewer而言与直连以太网没区别。
实践中,桥接脚本应考虑线程、缓冲和退出条件,这里简化展示。也可以使用现成工具,比如socat (socat tcp-listen:3490,reuseaddr file:\\.\COM3,b115200,raw
)来实现类似功能。
串口DLT实施要点
同步与解析:确保PC端能正确区分消息边界。如果使用同步头,则每条消息前会有0x444C等标识,Viewer配置SyncSerialHeader=1即可。如果无同步头,Viewer需从数据流中根据Length自行分帧。通常DLT Viewer有容错处理,但可能在丢字节时不同步。为安全,可启用同步头。
性能:串口速率低,建议降低日志频度或使用Non-Verbose模式。可通过设置日志级别阈值只输出WARN以上等级以减少数据量。同时Traffic Shaping也可在DLT配置中对串口通道设定,如限50KB/s以避免溢出。
可靠性:UART没有确认机制,若对日志可靠性要求高,可考虑在串口协议上加简单校验。GENIVI 串口协议包含CRC校验,可以参考实现。如果日志丢失不可接受,则串口可能不适合作为唯一日志输出,应配合NVM存储关键日志等策略。
通过上述方案,即使在无网络环境下,依然可以使用DLT收集日志。这对于资源受限的ECU(如某些从控制器)或台架调试时没有以太网设备的情况,非常实用。
DLT Viewer 使用详解
DLT Viewer 是由GENIVI提供的用于查看、控制DLT日志的PC端图形工具。它功能强大,支持多连接、过滤、搜索、导出等。本节介绍如何使用DLT Viewer 连接ECU、加载解析文件、过滤分析日志,以及一些常见技巧。
连接 ECUs
打开DLT Viewer后,首先需要建立与ECU的连接。常用的连接方式有:
TCP/IP 连接:这是最常用方式。在Viewer中选择“Network Connection”,输入目标 ECU 的IP地址和端口(默认为3490)。确保ECU上的DLT通信通道(如SoAd配置的TCP Server)已打开监听。点击连接后,Viewer会尝试建立TCP连接。一旦连接成功,ECU发送的DLT消息会源源不断地显示在日志窗口中。对于一个包含多个ECU的系统,可以在Viewer中同时打开多个连接,每个连接对应一个IP/端口,Viewer会将不同ECU的日志区分显示(通常根据ECU ID字段)。
串口连接:如前述,如ECU通过串口输出DLT,Viewer本身可以直接连接串口。在“Serial Connection”中选择相应的COM端口和波特率。前提是需要配置本地DLT daemon的串口模式或使用桥接程序。使用桥接的话,Viewer还是配TCP,此处不多赘述。直接串口连接的场景多见于运行Linux的设备通过USB串口输出DLT日志,Viewer可以ssh隧道+串口组合方式工作。对于Classic ECU,更多还是通过上述桥接模式来利用Viewer。
文件离线查看:Viewer也可打开已经保存的*.dlt日志文件进行浏览。通过File->Open DLT File即可。这种模式下没有实时数据,但可以使用Viewer的过滤、解析功能对历史日志进行分析。
连接安全性:如果ECU网络有防火墙或路由,需要确保3490端口开放。部分设置下可能通过DoIP网关连接,这需要配置对应静态IP。DLT Viewer目前不支持加密传输(如TLS),连接通道应在安全环境下使用。
建立连接后,Viewer日志窗口会出现来自ECU的消息列表。如果没有任何输出,需要检查ECU端DLT是否激活、过滤级别是否太高(例如全OFF),以及网络是否通畅等。
加载 ECU 描述文件
当使用Non-Verbose模式时,这一步至关重要。描述文件(Fibex *.xml或ARXML等)包含了解析日志Message ID所需的全部信息。DLT Viewer提供“载入描述文件”功能:
在Viewer菜单栏,选择 File -> Load ECU Description(或类似选项)。选择供应商提供的Fibex文件(一般扩展名
.xml
或.fibex
)。加载后,Viewer内部会建立Message ID到消息定义的映射表。若系统中有多个ECU,各自有独立描述文件,需要分别加载。Viewer支持在Connections窗口选中某个ECU连接,然后加载对应文件,使之只应用于该ECU。文件中一般含有ECU标识,如果匹配Viewer所见ECU ID,则会自动关联。
加载成功后,之前显示为原始Message ID和参数的日志行会立即被翻译。Viewer会将那些Non-Verbose消息替换为可读的字符串。如果加载前已经接收了一些消息,Viewer通常也会对其重新解析(有时需要重新刷新视图),实现**“非冗余数据回溯”**——即对已收到但未解析的日志进行回溯式解析,填入正确文本。
除Fibex外,Viewer也支持*.ecu文件(GENIVI DLT Extract格式)和AUTOSAR ARXML(如果包含Log&Trace提取)作为描述输入。不同文件可能需要在Load对话框选择格式。Fibex是应用最广泛的格式。
一旦描述文件加载正确,Non-Verbose模式下的日志观看体验将和Verbose模式几乎无异:可以看到完整的日志文本、变量值以及变量名和单位等信息。未加载前这些日志通常只显示十六进制数据或者“UNKNOWN”。
如果在Viewer中看到大量Message ID无法识别的日志,应立即确认是否已加载正确版本的描述文件。特别是在ECU软件更新后,Message ID 分配可能改变,需使用对应版本的描述文件。另外,Viewer可以配置自动加载:比如在Connections属性里填入描述文件路径,这样每次连接时会自动应用解析,防止忘记加载。
日志过滤与查询
DLT Viewer提供强大的过滤功能,帮助用户在海量日志中聚焦所关心的信息。主要的过滤手段有:
按日志等级过滤:界面上通常有快速按钮,可选择只显示>=某级别的日志。例如只看Warning以上,则Info和Debug级的全部隐藏。也可以组合筛选,如仅Error和Fatal。这利用的是DLT每条日志的level字段。
按应用/上下文过滤:Viewer会列出当前日志中出现的所有 Application ID 和 Context ID。用户可以勾选需要的应用或Context,只显示这些来源的日志。例如选中App="ENGN"可以只看引擎模块日志。对于特定Context(如APP=DEM, CTX=DTC)也可单独过滤。这样调试某模块时,其它无关日志不会干扰视线。
按ECU过滤:如果Viewer连了多台ECU,同时查看多个流,可以在Filters中按ECUID筛选某一台的日志(或进行比较)。ECU ID 在DLT消息标准头Byte4-7发送,因此Viewer知道每条日志来自哪个ECU。
文本搜索过滤:Viewer提供实时搜索框,可以输入关键字,界面仅显示消息内容包含该关键字的日志。支持正则表达式搜索和大小写匹配等。对于定位特定事件(如包含字符串"ERROR1"的日志),非常高效。也可以逐条跳转匹配项。
高级过滤规则:Viewer允许创建复杂规则组合,比如“App==ENGN AND Level>=ERROR AND Message contains 'sensor'”。可以保存为filter文件以便反复使用。通过这样的过滤,可一次性筛选出多条件满足的日志集合。
使用过滤不会丢弃日志,只是隐藏不符条件的。用户可以随时清除过滤查看全部日志。推荐在调试不同模块时充分利用过滤,将注意力集中在相关的信息上,减少干扰。
此外,Viewer还有高亮功能,可以设定某些模式的日志用不同颜色显示。例如Fatal和Error级日志用红色粗体,以便一眼发现严重错误;特定Context的日志设为蓝色以区分。这些在Filter/Highlight设置中可以配置规则。良好的高亮有助于长时间监控时快速捕捉异常。
日志分析与导出
DLT Viewer 不仅能实时查看,还提供一些分析和导出工具:
时间排序与统计:Viewer按照时间戳对日志排序。可以在界面上看每条日志的相对时间。有的版本支持显示时间差(两条日志的时间间隔)。通过观察时间戳,能分析系统性能,例如某操作耗时多久。Viewer也提供Timeline视图,将日志发生按时间轴排列,有助于分析并发事件。
错误检查:如果ECU实现了消息计数(Message Counter),Viewer可以检测是否有消息丢失(计数不连续)。当发现计数跳变,往往意味着中间某些消息在传输中丢失。Viewer可能在日志中插入标记或警告,提醒用户注意带宽问题或链路不稳。
导出日志:可以将当前日志列表保存为文件。支持格式包括:DLT文件(二进制原始格式,扩展名.dlt)、文本/CSV(解析后的人类可读文本)以及PCAP(如果日志与网络报文相关联,可以导出pcap用于网络分析)。常用的是文本导出:File->Save as TXT,会将屏幕上显示的日志(可选是否包含所有字段)输出为txt文件,方便共享或做进一步处理。
导出过滤结果:应用了过滤后,可以只导出过滤后的日志子集。例如在现场采集了一天的.dlt文件,回来用Viewer筛选出其中错误日志,然后将这些错误日志单独保存为一个.txt,这样体积小且聚焦问题,便于分析和报告。
统计报告:一些版本的Viewer或配套工具,可以对日志进行频次统计(比如某错误出现多少次)或者事件序列提取。这超出了Viewer本身,但通过将.dlt文件导出,再编写脚本解析,也可以实现。例如根据日志关键字统计出现次数等。
总的来说,DLT Viewer基本覆盖了日志分析的各个方面。从在线监控到离线分析,它都能胜任。关键在于善用其功能:连接、解析、过滤、导出结合起来,可以快速定位问题并拿出证据。
非冗余数据回溯与注意事项
当ECU使用Non-Verbose模式时,有几点在Viewer端需要留意:
确保描述文件匹配:如果描述文件与ECU软件版本不符,解析将出错。表现为日志显示的文本错乱,参数位置不对,甚至解不出内容。这时应该获取正确版本的fibex文件并重新加载。可以通过比对ECU软件版本号来确认,一般描述文件里会有版本说明。
回溯解析:如前所述,Viewer在加载描述文件后会尝试解析此前缓存的Message ID。这个“回溯”是有范围的,Viewer通常只缓存一定数量最近的消息用于回溯。因此最好在刚连接时就加载描述文件,避免错过最初一批日志的解析。如果加载晚了,一部分早期日志可能解析不了,需要再次获取或者手动解码。
多ECU文件:对于多个ECU并行的情况,需确保加载的描述文件正确关联各ECU。不小心把ECU A的fibex用在ECU B的连接上,就可能出现解析错乱。Viewer支持针对每个ECU连接分别指定文件,所以加载时要选中正确的Connection再Load。
刷新与重置:有时加载文件后已有的日志没有即时更新显示,可尝试在Viewer里执行Refresh或断开重连。通常稍等片刻也会自行更新。
通过以上方式,DLT Viewer 能够最大程度还原非冗余日志的信息,实现和冗余模式几乎相同的可读性。这正是Non-Verbose模式设计的初衷:用离线换在线,换取运行时性能。
性能与带宽优化策略
在使用DLT记录大量日志时,必须考虑对系统性能和通信带宽的影响。错误配置的日志系统可能导致总线拥塞、CPU过载甚至影响正常功能。以下讨论几种优化策略,以在收集有价值信息的同时,将开销降至最低。
日志过滤策略
合理设置日志级别阈值是控制日志量的首要手段。在配置中,应根据每个模块的重要性和阶段选择适当的默认级别。例如,安全相关模块可以默认INFO或更详细,以捕获运行细节,而稳定的成熟模块可默认WARN以减少无谓信息。在运行中,通过控制命令动态调整级别。调试某问题时临时调低阈值,只针对需要的模块,其它部分仍保持较高阈值。这种按需放宽和及时恢复策略可以避免长期输出大量冗余日志。
此外,DLT模块本身也会在Filter层对不需要的消息直接丢弃。因此确保过滤配置正确:例如已经关闭的Trace不要让SW-C持续发送,可以直接在DLT过滤层关掉Trace消息,以免浪费带宽和处理时间。SW-C端也应配合——收到级别通知后,尽量停止产生无用日志(双重过滤)。
带宽整形
对于通过以太网等高速总线输出DLT日志的情况,带宽通常不是瓶颈。但在共享带宽或低速链路(CAN、LIN、UART)上,日志可能与正常通信争夺带宽。DLT 的Traffic Shaping功能提供了解决手段。
通过配置每个LogChannel的DLTLogChannelTrafficShapingBandwidth
,可以设定一个大致的带宽上限。DLT 模块据此控制发送速率,典型做法是在内部计算最近发送量,如果超过阈值则暂缓后续消息的发送,等待窗口刷新。这类似漏桶/令牌桶算法调控流量。这样可确保即使日志量突然激增,也不会完全挤占总线。超出的日志暂存于DLT缓冲中,等有带宽再发送。
需要平衡的是延迟与丢弃:如果缓冲较大,整形会引起日志延迟输出(看日志有滞后);缓冲小则可能不得不丢弃部分日志来腾空间。可以根据系统实时性要求调整带宽值和缓冲大小。例如UART 115200bps,可设带宽11KB/s,让DLT匀速输出,不致于持续溢出。
在没有TrafficShaping功能的情况下,也可以手动通过调节日志级别来控制带宽——比如发现总线负载高,就临时把大部分模块调到ERROR,只保留关键模块INFO,从源头减少数据。
缓冲区与存储策略
DLT 使用环形缓冲存储待发送的日志消息。合理设置缓冲区大小和溢出策略对性能很重要:
缓冲区大小:应能容纳一定时间窗口内的峰值日志量。过小缓冲会导致峰值一来即溢出丢包;过大缓冲则占用内存过多且可能引起日志延迟。可以根据经验和测试确定:如某模块启动时会产生100条INFO日志,每条100字节,则需要至少10KB缓冲保证不丢。如果内存允许可取裕量,比如配置20KB。
溢出策略:DROP vs OVERWRITE 各有利弊。选择DROP(丢弃新日志)时,遇到高负荷,新日志不记录,这样保护了已有日志不被覆盖,但可能错过后续关键错误;选择OVERWRITE(覆盖旧日志)则保证最新的信息总是保留,但可能丢失最开始的线索。开发者需根据场景:如果问题的根源通常在最初发生,则保留老日志重要,宜选Drop Tail;如果更关心最新状况,选Overwrite头部更合适。也可以针对不同Channel采用不同策略(比如内存日志环形覆盖,串口日志宁可丢新保留旧)。
Flush触发:某些DLT实现提供刷新控制,如满缓冲时立刻触发发送而非等定时调度,或者遇Fatal错误立即flush所有缓存。调整这些策略可减少关键日志延迟。如果没有自动flush,外部也可通过SendBufferStatus命令提示ECU flush(视实现而定)。
NVM存储:为了防止严重故障时日志丢失,可以开启DLT的NvRAMSupport。这样在系统崩溃前(如果有机会)可以调用 StoreConfiguration 将日志或至少当前过滤配置保存。更加典型的做法是结合DEM:出现致命故障时,将最近N条DLT日志存入循环缓冲NVM区,下次开机时可以上报或分析。这需要一点自定义开发,但能提高日志可靠性。
多通道分流
合理利用 DLT 的多通道能力,可以实现日志的分流,从而降低单一通道的负载,并实现优先级隔离:
按重要性分流:例如配置两个日志通道:Channel0走以太网全量输出,Channel1走CAN总线但只输出Fatal/Error。这使得在没有连接以太网调试时,关键错误还能通过CAN网关上传,其他详细日志则不占用CAN带宽。又如高优先级安全日志和一般调试日志分开两个以太网端口,高优先级端口可给更大带宽和实时保证。
按模块分流:将不同功能域的日志发送到不同介质。例如动力域ECU同时有LIN和CAN,可以让底盘相关日志走CAN,车身舒适日志走LIN,这样互不干扰,各自总线带宽占用较为可控。DLT 支持配置每个SW-C Context所属的通道。
按用途分流:可以设置一个通道专用于定期状态上报(例如每秒输出一次关键标尺数据,用于性能监控),另一个通道用于事件驱动日志。前者数据量小而定时,可给予稳定带宽;后者突发性强,通过TrafficShaping来控制。
互为备份:有时可以配置两个通道输出相同的日志信息,一个高速实时,一个低速备援。例如Ethernet实时输出,另外串口同步输出关键信息并存Log文件。如果网络日志由于环境问题丢失,还能从串口记录中找回关键错误。这种双通道需要SW-C调用两次日志发送或DLT模块支持一条日志到多目标,目前DLT标准没有自动广播功能,只能由应用层重复发送到不同Context(每Context绑不同通道)来实现。
使用多通道要小心规划,避免无谓的重复造成更多开销。通常应根据实际需要选择性地复用信息。对于资源足够的系统,多通道是性能优化的有效手段,可以平衡网络负载并增加日志系统的健壮性。
其他优化措施
除了上述主要策略,还有一些零散的建议:
非冗余模式:前文已述,Non-Verbose模式通过牺牲一定便利性换取大幅带宽节省,是性能优化的关键策略之一。强烈建议在Release版本中使用Non-Verbose模式,并将fibex文件与ECU软件版本严格对应管理。冗余模式仅在开发联调阶段开启。
减少格式化开销:即使Non-Verbose不发送文本,ECU端也可能进行了字符串格式化(这取决于实现,一些实现Verbose模式下实时格式化,Non-Verbose则不格式化)。为了进一步减轻CPU负担,可以在开发中少用复杂格式符。或者在编译选项上定义一些宏使得Verbose模式下也简化处理。具体优化可参照DLT SWS和实现文档。
定期监视与限流:对日志系统本身进行监控也是优化一环。例如在ECU上实现一个简单的计数器,记录每分钟发送了多少字节日志,若连续几分钟超过阈值则报警或者自动上调全局过滤级别(比如把DefaultLogLevel暂时提到Error),防止日志暴涨影响正常通信。这样的机制相当于自我调节,可作为fail-safe措施。
调度优先级:DLT 模块和相关任务应配置适当优先级。通常日志发送属于后台低优先任务,不能抢占关键实时任务。因此要在OSEK调度中将DLT任务优先级设定低于控制任务,防止大批日志处理占用CPU导致控制周期延迟。但也不能太低以致从不调度尤其在满负荷下。因此建议DLT任务优先级略高于空闲任务Idle,低于一切周期任务。这样只有在CPU有空闲时才运行日志发送,不干扰主业务。
分布式日志收集:针对车载网络中多个ECU都有DLT日志的情况,可考虑引入集中式网关或诊断主机,将日志汇聚、过滤后再输出。这可以减轻每个ECU独立对付大量日志的负担。不过这属于系统架构层面的优化,超出DLT模块本身范畴。
通过以上综合运用,DLT日志系统在提供充分信息的同时,能够“隐身”于系统,不至于拖垮ECU资源或者淹没通信总线。正如一句话所说:“最有用的日志是恰到好处的日志”——既捕获问题,又不影响系统运行。
Non-Verbose 模式实践
Non-Verbose模式的有效实施涉及开发流程和工具链的配合。从消息ID的分配到描述文件的管理,再到CI流程的检查,均需要一定规范。下面分享Non-Verbose模式落地的一些实践经验。
消息 ID 管理
Message ID的管理是Non-Verbose模式的核心。每个Message ID必须唯一并且固定地对应一条日志消息的格式。良好的ID管理策略包括:
集中定义:在代码层面,将所有使用DLT的日志消息ID集中管理。例如可建立一个header文件或配置表,列出
#define DLT_MSG_TemperatureMeasurement 0x1001
等。这种集中定义便于避免冲突和查重。如果使用AUTOSAR配置工具,则应由工具在生成的Dlt_Cfg.h中统一定义所有Message ID符号。范围划分:为不同的模块或组件分配不同ID区间。例如引擎相关日志用0x1000-0x10FF,变速箱用0x1100-0x11FF等。这样各团队在各自范围内定义ID,互不干扰。即使不使用全区间,预留一些空间也无妨。这可以通过人工约定,或者在配置工具中按模块前缀自动生成(有些工具可以根据SW-C自动添加偏移)。
自动分配:人工管理ID在大型项目中易出错。Vector DaVinci等提供自动计算MessageID的功能。通常根据AppID、ContextID、以及在配置中消息出现的顺序计算一个Hash或序号作为ID。这种自动分配减少了冲突风险,但要确保每次配置生成后导出的描述文件更新到位,否则代码和解析器的ID映射会不一致。使用自动分配时,可以锁定种子或算法,以保证软件版本更新时ID不会大面积变化(除非新增/删除日志)。
长度选择:Message ID 字段长度在DLT协议中没有硬性规定,可以是16位或32位(一般归入Payload)。16位ID最多支持65535个不同消息,对大多数ECU足够。如果日志种类非常多,可以用32位ID。Fibex描述文件支持任意ID值,但使用时要保证Viewer兼容性。
命名和注释:给每个消息ID起一个有意义的名字,如
MSGID_OVERTEMP_WARNING
,并在定义处注释用途。这对later维护很重要。当问题出现需要查找某个ID时,良好的命名显著提高效率。
消息ID管理的目标是:每个日志语句在代码和描述文件中一一对应,永不混淆。为此需要开发团队纪律性地遵守定义规范。一旦某条日志的格式改变,应该视为不同消息,分配新ID,而旧ID弃用。这避免用相同ID承载不同格式数据导致解析错误。
ARXML/FIBEX 映射生成
AUTOSAR 开发环境下,Non-Verbose模式的描述文件往往可以通过配置直接生成。例如:
Vector DaVinci Configurator在生成ECU配置时,可同时生成对应的Log&Trace Extract XML。其中包含ECU的所有ApplicationID、ContextID和MessageID的信息。这通常称为ECU Extract文件,可提供给DLT Viewer加载解析。
若使用其他配置方式,也可通过AUTOSAR提供的模板手工编写Fibex文件,但工作量较大且易错。更好的办法是写一个脚本,从源代码或配置中提取信息生成Fibex。例如一些项目中约定所有DLT日志使用特定宏包裹,通过扫描源代码可以收集到格式字符串、参数类型,然后赋予ID生成Fibex。
ARXML vs Fibex:AUTOSAR 4.x版本,官方提供一种Log&Trace Extract ARXML的格式,可以直接被DLT Viewer识别。然而很多工具(包括GENIVI原版)仍使用ASAM Fibex标准。这两者在本质内容上类似,只是元素命名和结构略有不同。可以通过转换工具将ARXML转换为Fibex。也有OEM要求供应商提供Fibex,以便与整车其他数据(如Autosar通信矩阵)合并。因此一般建议输出Fibex3.1格式文件。
Fibex文件结构:每个Message定义为一个Frame,Frame里包含多个Signal代表参数。Frame有ID属性(通常填MessageID的十进制),有名称(可由AppID+Context+简短描述组成),Frame下的Signal顺序和属性应与参数一致,包括Signal长度(TypeLength)、数据类型(如Unsigned32)、是否有单位等。静态文本部分可作为Signal描述(Desc)填在一个零长的占位Signal里。由于Fibex主要为网络协议设计,一些元素可能用不到,比如消息周期等,可忽略。务必确保Frame和Signal的ID/名称等不冲突,并附带ECU和Cluster定义。
文件合并:如果每个SW-C供应商各自提供一份Fibex,需要由系统集成在整车级将它们合并成一个综合Fibex。合并时要留意Frame ID全局唯一。一般来说,一个ECU一个Fibex足矣,除非ECU非常复杂划分给多方开发。
版本控制:将Fibex文件纳入配置管理,与代码版本同步。可在文件内的ECU节写入软件版本号,DLT Viewer加载时能看到。例如
<ECU VERSION="1.2.3"/>
等。这样在分析日志时能核对版本,避免用错文件。
通过工具链生成和维护ARXML/Fibex,大大减轻了人工同步错误。理想情况下,开发人员添加一条DLT日志,编译配置生成新的Fibex,CI自动验证Fibex和代码匹配,然后交付测试使用——整个流程尽可能自动化,减少人为失误。
Viewer 显示逻辑解析
DLT Viewer加载描述文件后,其显示逻辑如下:
当一条Non-Verbose日志抵达Viewer:
Viewer读取该消息的ECU ID和Message ID。先根据ECU ID找到对应的描述数据表(已加载的Fibex中ECU段)。
在该表中,查找Message ID匹配的Frame定义。如果找到,则获取该Frame下的静态描述(若有)和各Signal定义。
Viewer从DLT消息中解析出参数字节流,然后依据Signal定义逐个解释:
- 按顺序将字节解析为Signal规定的数据类型(注意大小端转换)。
- 如果Signal有名称和单位,则在显示时附加。例如参数值
22.1
显示为reading=22.1 Kelvin
。 - 静态文本Signal(占位的Desc)会被直接当作字符串插入。例如Frame描述含"Temperature measurement", 则Viewer会在组装消息字符串时加上这段静态前缀。
组合输出:Viewer将静态文本、各参数名值拼成最终可读字符串,并按照Verbose格式的样子显示。如果某参数类型无法识别,则以hex形式显示以提示可能解析错误。
如果未找到Message ID对应的Frame(或者Frame定义不完整),Viewer通常会将该条日志标记为“Non verbose: ID=0xXXXX, Data=[...raw hex...]”。这提醒用户解析失败,需要检查描述文件。
对于Trace和控制消息,Viewer也类似处理。Trace消息也有Message ID(可认为Trace事件类型ID),但通常Trace元数据简单,Viewer可能直接有基本解码而不需要Fibex,例如Trace的MTIN就指明了trace事件名称,这种情况下Fibex文件主要提供上下文和可能的参数含义。
简而言之,DLT Viewer就是按照协议规定的方式,将Non-Verbose消息+描述文件重组成Verbose的样子。这套逻辑关键取决于描述文件的正确性和完备性。一旦描述文件更新,例如修正了某Signal类型,Viewer会立刻按新定义重新解析已有记录。因此在调试解析问题时,可以更新Fibex重新加载,然后Use "Reload and Re-parse"功能(如果有)验证新定义效果。
从性能上,Viewer解析本地Fibex比从ECU收到Verbose字符串消耗低很多,而且可以在PC上灵活搜索、格式化。但缺点是描述文件可能出现不匹配问题。因此开发时推荐同时启用Verbose输出以核对Fibex正确性:即让ECU同时发Verbose和Non-Verbose两条相同消息,对比Viewer显示是否一致。确认无误后,量产再关闭Verbose版本。这种双发送验证虽费点时间,但可预防解析偏差导致误判。
CI 检查流程
引入Non-Verbose模式后,构建一个自动化的CI(持续集成)检查流程来保证代码、配置、描述文件的一致性非常重要:
静态检查:编写脚本扫描代码仓库中所有DLT日志的宏调用或字符串标识,与描述文件里的定义对比。例如找出代码中新出现但Fibex中没有的Message ID,或者Fibex有但代码未引用的废弃ID。这种检查可以基于正则表达式提取,也可以利用编译产物(如Dlt_Cfg.h中IDs列表)来对比Fibex XML。
ID 冲突检查:扫描描述文件,确保没有重复的Frame ID或信号ID。这通常通过XML解析器即可做到。如果发现重复,应在CI中报错。因为重复ID会导致解析混乱,必须杜绝。
格式一致性:更复杂的,可以模拟解析。即CI脚本取代码中的某条日志格式字符串,按照Fibex定义尝试编码并解码,看能否一致。这需要能拿到代码中的格式及类型信息。如果采用集中配置生成IDs,那么可在生成时输出一个映射表,例如CSV列出ID、字符串模板、参数列表,然后CI根据该CSV与Fibex核对每个ID是否一一对应且参数类型吻合。
版本匹配:CI可以强制要求每次软件版本升级必须相应更新描述文件的版本号,并校验提交记录中两者是否同步更改,否则提醒开发者。这样避免忘记交付新Fibex给测试团队的情况。
Runtime验证:如果有自动化测试环境,CI最后部署的构建可以跑一个Smoke test,让ECU输出几条已知日志,PC这边用dlt-control/dlt-viewer-cli接收并用Fibex解析,比对解析结果是否等于预期字符串。这是最终端到端验证Non-Verbose正确性的有效方式。
将上述检查纳入CI流水线,可以在开发的早期就捕获纰漏,减少后期调试混乱。同时,这些产出的对照表、CSV等,也能成为很好的文档,供开发和测试人员参考(比如快速知道某ID属于哪个模块哪个日志)。
可以说,在Non-Verbose模式下,“正确的配置即正确的代码”的理念尤为突出。CI检查确保了这一点,使DLT真正成为可靠的故障诊断利器,而不会因为人为管理不善而引入新的问题。
与 DEM/DET 集成
AUTOSAR DLT 模块除了服务普通调试日志,还能与诊断错误管理DEM和开发错误追踪DET模块协同工作,将系统错误信息统一地记录和上报。以下介绍这方面的集成要点:
诊断事件记录到 DLT
**DEM(Diagnostic Event Manager)**管理DTC(诊断故障码)等事件。当某个DTC发生或恢复时,DEM会调用相应接口记录内部状态。通过与DLT结合,可以让这些事件也输出日志,例如“DTC P0301(失火)已存储”。具体实现有几种方式:
DEM调用DLT API:在DEM配置中,可以为每个Event定义NvM存储和报警处理。同样可以增加一个用户自定义的Callback(比如DemEventStatusChanged),实现中调用DLT输出日志。Dem提供的Hook如 Dem_SetEventStatus()的返回结果钩子,或者扩展点可以用于此。这样每当故障码状态改变,DEM除了内部处理,也额外发送一条DLT日志带上事件ID、状态等信息。外部工程师通过DLT Viewer即可及时看到DTC的动态。
DEM扩展组件:有些AUTOSAR实现将DEM事件和Dlt模块直接关联。当重大事件发生时,DEM会触发Dlt的一条控制消息或特殊日志。例如“ENV1: CrashEvent occurred, FreezeFrame captured”。具体机制因供应商而异,但目标一致:利用DLT的输出能力,把过去需要进维修站读取的故障记录,转变为运行时的可见日志,有助于远程故障判断。
DEM状态快照:在出现严重故障后,通过DLT injection功能甚至可以请求DEM输出某个DTC的快照数据。DEM储存FreezeFrame在NvM里,平时只能通过UDS工具读。如果DLT injection配置一个服务,让外部发出“Dump DTC 0x1234 freeze frame”请求,SW-C(或者在Complex Driver中)调用Dem接口读出数据并通过DLT日志发回。这就大大增强了远程诊断的能力。当然实现较复杂,需要慎重设计注入服务。
总体来说,将DEM和DLT结合,能把传统“静态诊断”变为“动态诊断”。在车联网远程运维中,如果车辆报告发动机故障灯亮,后台可下发指令要求DLT输出相关DTC信息,不用等专业技师现场读取,提升效率。
与开发错误追踪(DET)协同
**DET(Development Error Tracer)**模块用于在开发阶段捕获各模块API调用时的参数错误等开发错误。通常DET在错误发生时调用Det_ReportError存储错误信息,或在调试器上断言。通过DLT,可以让这些开发错误在运行时也上报到外部日志:
DET -> DLT:AUTOSAR DLT标准明确指出DLT模块可接收来自DET和DEM的日志信息。实际实现中,有时会将Det_ReportError实现成调用DLT,如:
Std_ReturnType Det_ReportError(uint16 ModuleId, uint8 InstanceId, uint8 ApiId, uint8 ErrorId) { // 组装错误信息字符串 char msg[50]; snprintf(msg, sizeof(msg), "DET:E=%u in Module=%u API=%u", ErrorId, ModuleId, ApiId); // 输出DLT日志(假设DLT已注册DET的context) Dlt_SendLogMessage(detContext, DLT_LOG_ERROR, msg); // 记录全局变量或断言之类 lastDetError = ErrorId; return E_OK; }
这样每当任何一个模块通过DET报错,它不仅被记录在DET内部表,也同时发送一条DLT Error日志。DLT Viewer上就能汇总所有开发错误,方便发现配置或调用不当的问题。
DLT DevErrorDetect:DLT 模块本身也可以使用DET报告错误,比如非法参数、缓冲溢出等。如果配置打开DltDevErrorDetect,DLT内部的Det_ReportError调用也能转为DLT日志。不过这属于DLT自检错误,一般只有配置不当才会触发。
错误等级统一:通常DET错误都属于严重问题,应映射为DLT的Error或Fatal级日志。通过统一的DLT通道输出后,可以利用Viewer过滤“All Errors”迅速看到系统所有报错,不论来自应用还是BSW。DET错误往往有Module和ErrorId编码,不直观,建议在DLT输出时翻译成可读消息(如通过查表转换成 "CANIF_E_INVALID_TXPDUID" 之类)。
开销考虑:DET错误通常发生频率不高,输出DLT对性能无大碍。如果某错误在循环中持续报,那本身说明逻辑有严重问题,需要开发者修正,而不是担心日志性能。甚至可以设置DLT对重复的DET错误抑制输出,比如在Det_ReportError中检查如果同样错误连报很多次,仅第一次上报DLT,后续忽略,以免刷屏。
将DET接入DLT把以往“黑匣子”里的开发错误公之于众,极大方便了软件集成调试。特别是在整车测试时,不需要单独工具就能获得底层BSW错误信息。例如内存池满、非法调度调用等,以前可能只能靠经验猜,现在DLT日志有DET报错,一目了然。
最后,需要注意DEM/DET日志也需描述文件:DEM/DET输出如果使用Non-Verbose模式,也应该在Fibex里写入对应Message ID和文本。例如 DET的错误可以设计一个固定格式:"DET Error: Module %d Api %d Error %d" 绑定某ID,否则外部无法解析具体内容。但由于DET错误种类有限,也可直接Verbose输出字符串。视项目情况决定。
与 SoAd、DoIP 协同
AUTOSAR通信栈中,与DLT日志传输密切相关的模块是SoAd(Socket Adapter)和DoIP(Diagnostics over IP)。DLT日志往往走以太网,而以太网在AUTOSAR CP中由SoAd提供Socket接口服务。在某些架构中,DLT消息可能会与DoIP共存于同一物理网络。下面讨论DLT通过DoIP通道传输的配置考虑,以及验证要点。
DLT 通过 DoIP 通道传输
DoIP模块是AUTOSAR针对以太网诊断通信的实现,专用于处理UDS诊断协议在IP上的封装(ISO 13400)。DoIP自身监听TCP的默认端口13400,用于诊断会话。DLT并不依赖DoIP模块,因为DLT不遵循诊断协议,而是自行通过TCP/UDP发送。不过,在实际车辆网络中,通常会重用车辆的诊断以太网通道来传输DLT日志:
- 物理通道共用:大多数车辆只在OBD接口或以太网上开通一个物理以太网口供外部设备连接(连接车机或网关)。通过这个接口,既要跑DoIP诊断,又希望获取DLT日志。因此DLT日志流通常与DoIP共享同一根网线,甚至经过同一网关转发。但它们逻辑上独立:DoIP占用13400端口,DLT占用3490端口(或其他配置的端口)。外部测试仪可以同时对同一ECU打开两个TCP连接,分别进行诊断会话和日志会话,两者互不干扰。
SoAd配置:确保SoAd模块配置了两个Socket Server:一个给DoIP(通常已配置,TCP 13400),一个给DLT日志(TCP 3490)。SoAd需要有各自的Pdu集合和Connection。Vector的配置示例中,会在SoAd/SocketConnection下有一项如 "TCP_DLT_Server" 指定 <Port>3490,<Protocol> TCP,<Type> Server,<AutomotiveProtocol> None(表示纯裸数据)。同时SoAd应将收到的数据绑定到前述的 Pdu_DLT_Rx_SoAdToPduR
,发送数据的绑定 Pdu_DLT_Tx_PduRToSoAd
。这样SoAd实例化出一个监听3490端口的socket。
网络层设置:DoIP模块通常管理网络唤醒、Vehicle Announcement等,对于DLT来说这些不适用。如果DLT仅用于维修调试,那么ECU即使不收到DoIP Activation,也可以接受DLT连接。因此要注意唤醒策略:有的车辆以太网在正常行驶不启用诊断通道,为节能需要在DoIP Activation Line拉高时才通电网络。如果要远程实时获取DLT日志,可能需要确保以太网持续供电,或者在DLT重要日志(如故障)出现时主动触发唤醒网络。这涉及整车设计,不在DLT模块自身配置范围。但作为调试人员要知晓,如果物理层没唤醒,DLT再多也发不出去。
IP地址与路由:DoIP ECU通常使用静态IP或DHCP获取IP。DLT Viewer连接需要知道ECU IP地址。通常在整车测试中,会先通过DoIP的Vehicle Announcement获取各ECU IP,然后脚本配置DLT Viewer连对应IP:3490。对于单ECU,可以直接固定IP。需要确保PC和ECU在一个IP网段或者已配置路由。
UDP支持:DLT Viewer也支持UDP模式连接。DLT模块也可通过UDP广播日志,这样无需建立连接即可监听。这有利于比如同时监听多个ECU日志。但UDP不可靠、乱序,适合监控不良,不适合正式记录。配置上,可在SoAd增加UDP socket,对应Pdu绑定DLT。Viewer端选择UDP模式输入ECU IP和端口即可。很多项目还是偏好TCP方式,因为可靠有序。
配置与验证要点
配置完成后,需要验证DLT日志通过DoIP网络的正常工作:
并发通信测试:同时进行UDS会话和DLT日志发送,检查两者是否互相干扰。在ECU端,DoIP和DLT是不同Socket,不会直接干扰,但要注意带宽。如果一个ECU同时在跑大量DLT和大数据量UDS(如刷写),可能以太网带宽100Mbps绰绰有余,但ECU处理两者数据的能力需评估:PduR和SoAd同时处理两个流,可能队列积压。实际测试中可以发起一个大Memory读(UDS服务0x23)看看DLT日志是否延迟,或在大刷写期间看日志是否丢失。
资源占用:SoAd开两个Server意味着ECU上两套Socket资源,对一些资源紧张的微控制器要留意Socket Buffer大小配置,以及SoAd和PduR的配置表尺寸上限。如果日志量很大,也要调大SoAd Rx缓冲。
安全与关断:有的汽车以太网通信在某些模式下需要加密或者认证(比如OTA模式)。DLT流通常不加密,如果环境需要,也可以通过VPN隧道或后处理加密。但AUTOSAR CP里没有直接支持TLS的SoAd,因此在对接外部网时,DLT最好放在开发接口,不开放在生产车联网接口,以免敏感日志外泄。
工具验证:推荐使用Wireshark监听以太网数据包,验证DLT报文格式是否正确传输。Wireshark有DLT协议解析插件,可以直接看到DLT包结构。抓包可以确认ECU有无发出日志、端口对不对、长度字段是否正确等等。如果Viewer连不上,也可以用 telnet/netcat 工具尝试:
nc <ecu_ip> 3490
,看是否有二进制数据流出,以判断是网络问题还是Viewer问题。多跳网络:如果DLT Viewer不直接连ECU而是通过中间网关(比如车里网关或云端转发),需要整个链路支持TCP转发即可。DoIP网关不会管非13400端口,所以如果通过车载以太网网关,要配置它允许3490端口转发。实际有的网关可能默认阻断非标端口,这时需要在网关上特殊配置开放DLT端口,否则外部PC永远连不到ECU的DLT服务。
Adaptive关系:若ECU跑Adaptive和Classic混合,Adaptive部分也可用DLT,但Adaptive可能通过dlt-daemon对外开放不同端口(通常也是3490,Adaptive Foundation会复用)。此时外部看到的可能是两个来源的日志通过同一连接出来,需要ECU ID或APP ID区分(Adaptive应用通常有长一点的AppID)。需要在验证时看看Adaptive和Classic日志是否正确区分标识,避免混淆。
总之,与SoAd/DoIP的协同大多在配置网络通信层面。一旦通道打通,DLT模块的工作与前面章节并无二致。通过恰当配置和充分测试,可以保证诊断会话与日志传输在同一以太网上和平共处,满足调试和诊断的双重需求。
工具链协同:dlt-daemon、dlt-control、dlt-viewer-cli 使用
GENIVI DLT 不仅有Viewer图形界面,还包括后台守护进程和命令行工具,以支持Linux/Android等系统的日志管理。理解并善用这些工具,可以拓展DLT的应用范围,特别是在AUTOSAR Adaptive平台或Linux开发中。下面简述 dlt-daemon、dlt-control 和命令行查看工具的用法。
dlt-daemon (DLT 守护进程)
dlt-daemon 是运行在ECU上的后台服务程序,在AUTOSAR Adaptive或其他POSIX系统中使用。它主要功能包括:
收集日志:dlt-daemon 提供本地IPC接口(Unix Socket或FIFO),本机上的应用进程可以通过链接libdlt库,将日志发送给dlt-daemon。dlt-daemon缓存并管理来自多个进程的日志消息。
外部通信:dlt-daemon 监听TCP端口3490,以及可选的本地串口或UDP端口,根据配置而定。当外部DLT Viewer连接时,daemon将内部缓存的日志发送出去,并持续转发实时日志。同时它也接收来自Viewer的控制命令并分发给相应应用。dlt-daemon保证了单一出口,统一管理日志流。
控制协调:dlt-daemon会维护一份当前所有注册的 Application IDs 和 Context IDs 列表。当外部请求“GetLogInfo”时,daemon汇总此列表发送。当外部下达“SetLogLevel(AppX, LevelY)”命令时,daemon会找到对应AppX的进程,通过本地IPC把命令发送给该进程内的libdlt,libdlt再调用应用提供的回调或调整过滤。这种架构使Adaptive平台上多个应用的日志控制集中由daemon处理。
缓冲与存储:dlt-daemon可以设置缓存大小,以防外部未连接时暂存日志,防止丢失。还可配置“circular log”把日志写入本地文件以备稍后提取。某些Linux系统中会设置dlt-daemon将日志写本地文件(比如/var/log/dlt)以保存运行记录。
在Linux上使用DLT时,一般在系统启动时便拉起dlt-daemon(比如systemd服务),然后应用程序在运行时只需要:dlt_register_app("APP1", "Description")
、dlt_register_context(...)
,之后用 dlt_log_info(ctx, "message", param)
等接口输出日志,由libdlt发送给daemon。dlt-daemon默认配置监听3490,所以PC可以随时连上抓日志,而不需要应用直接开Socket。这解除了应用开发者处理网络的负担,也避免多应用各自连PC的麻烦。
配置dlt-daemon通常通过 /etc/dlt.conf
文件。其中可设置:
- TCP端口(默认3490,可改)、
- 串口设备(默认注释不用)、
- 日志文件存储路径和大小等。
dlt-daemon启动时读取配置,按照要求启动相应通信。
对于Classic Platform ECU,通常没有操作系统,不会运行dlt-daemon进程。但如果Classic ECU有以太网协议栈,也可在PC或Vehicle Gateway上运行一个dlt-daemon来充当日志汇聚。例如网关收集各CAN节点日志后通过统一接口给PC,这种架构比较复杂,一般只Adaptive用得到。
dlt-control (控制命令行工具)
dlt-control 是与dlt-daemon配套的CLI工具,用于从命令行发送DLT控制消息。在没有DLT Viewer图形界面的场景下(比如只有SSH终端连接设备),可以用它调整日志配置。用法概要:
基本命令格式:
dlt-control [选项] <hostname或serial_device>
常用选项包括:
-l <level>
:设置日志等级。结合-a <AppId>
和-c <ContextId>
可以指定范围。例如:dlt-control -l 2 -a APP1 -c CONT1 192.168.0.10
将APP1:CONT1级别设为ERROR(2)。dlt-control -l 5 -a APP* 192.168.0.10
将所有AppID以"APP"开头的上下文日志设为DEBUG(5)。dlt-control -l 0 192.168.0.10
将所有日志关闭(Level 0=OFF)。
-r <0/1>
:设置Trace状态。可类似地与 -a/-c 组合指定范围。-r 0
关闭,-r 1
开启。-d <level>
:设置默认Log等级(不带 -a/-c 则作用于Default)。-f <0/1>
:设置默认Trace状态。-j
:请求Log Info。Daemon返回当前注册的应用、上下文及各自当前等级的列表,dlt-control会打印在终端上。这对了解系统日志配置全貌很有用。-o
:Store Configuration,要求daemon将当前配置存入NVM。-g
:Reset to factory default,将配置重置。-t <ms>
:等待超时时间,默认1000ms,一般不用改。-p <port>
:指定TCP端口,如非3490时使用。-u
:使用Unix Domain Socket而非TCP。即操作本地daemon,不通过网络接口。
比如想查看当前有哪些应用在输出日志,可SSH登录ECU后运行:
dlt-control -j -u
这会让本地dlt-daemon列出所有App/Context及其状态。输出类似:
AppId: APP1 (Description) Contexts:
CONT1 Level=3 (WARN) Trace=OFF
CONT2 Level=4 (INFO) Trace=ON
AppId: APP2 (Desc2) Contexts:
MAIN Level=2 (ERROR) Trace=OFF
...
这样开发人员无需连接Viewer也能了解日志配置。
再例如,将所有日志打开Verbose:
dlt-control -l 6 -d 5 -f 1 192.168.0.10
这条命令含义:设所有Context日志等级=6(VERBOSE),默认日志等级=5(DEBUG),默认Trace状态=1(ON),目标IP为192.168.0.10。这实际上将整个系统日志调到最高详尽度。
dlt-control执行后,如果需要可以再用-j
查看确认效果。dlt-control 对于调试脚本化操作很有价值,可嵌入shell脚本,根据不同条件自动调整日志。例如检测到某错误出现,则调用dlt-control打开某模块DEBUG级别,收集更多数据一段时间再关闭。
dlt-viewer-cli / dlt-receive (命令行日志查看)
除了图形界面,有时我们希望在命令行环境下查看或保存DLT日志。这在远程SSH、无人值守记录或者CI中非常有用。GENIVI DLT提供了 dlt-receive
工具(有些发行版中叫 dlt-example-console-client
),其功能是作为一个控制台DLT客户端接收日志并输出。
dlt-receive 的典型用法:
dlt-receive [-a] [-o <outfile.dlt>] [<host>]
- 不加参数默认连接本地dlt-daemon(Unix Socket)。
- 加一个主机名则连接指定IP的3490端口。
-a
选项:将日志payload部分以ASCII打印。否则默认十六进制。这是因为没有描述文件情况下,它无法解析Non-Verbose,将原始数据也打出来给人看。如果带-a,则尝试把payload直接当字符串,如果payload本身是二进制则可能乱码。通常Verbose模式下用-a能直接看到日志文本。-o <file>
:将收到的日志以DLT文件格式存储到指定文件,不打印到屏幕。可用于长时间记录后拿到PC用Viewer打开分析。- 其他还有
-h
帮助、-p <port>
指定端口等。
例如SSH到某ECU终端,想简单看看实时日志:
dlt-receive -a 192.168.0.10
这会连接IP为192.168.0.10的DLT服务,然后不停地在当前终端打印收到的日志文本。如果日志有颜色信息或特殊字符,也会原样输出。可以按Ctrl+C中断。
如果想收集一段时间日志供稍后分析:
dlt-receive -o /tmp/testlog.dlt 192.168.0.10
它会连接后将日志二进制存到/tmp/testlog.dlt文件,不在终端显示。等合适时间按Ctrl+C停,它会优雅关闭文件(DLT文件有全局头需要在结束时写入统计信息)。
dlt-receive比较朴素,不会解析Non-Verbose。但我们可以配合 dlt-control
在CI脚本中使用:例如每夜构建后跑测试之前,用dlt-control打开大量日志,然后dlt-receive保存测试全过程日志,再关闭日志。这样得到的dlt文件可在问题发生时由开发者离线检查。
除了dlt-receive,另有 dlt-convert
等工具可以将DLT文件转成PCAP或文本。然而更直接的是使用dlt-viewer自带命令行参数。根据GENIVI文档,dlt-viewer本身可通过CLI执行转换。例如:
dlt-viewer -c input.dlt output.txt
据说可以将dlt二进制转为文本文件并退出。但这个通常要在有显示环境或特殊编译下才能用,CI中不如dlt-convert稳妥。
Linux环境下综合示例
假设我们有一台装有Linux的ECU(Adaptive Platform),上面跑dlt-daemon和若干应用;我们通过SSH来调试日志:
首先检查 dlt-daemon 是否运行:
ps -e | grep -i dlt
,应看到dlt-daemon
进程。如果没跑,可以通过systemctl start dlt
启动(具体服务名视环境)。查看当前已有的App:
dlt-control -j -u
列出所有应用和上下文。假设我们看到 App "ADAS" 下有Context "CAM"和"GNC"等。临时将"ADAS"应用所有日志打开Verbose:
dlt-control -l 6 -a ADAS -u
(这里-u表示本地)。这样ADAS模块的所有Context日志级别=VERBOSE。用 dlt-receive 在终端打印日志:
dlt-receive -a -u
。这会不断刷出日志,如果太多可以CTRL+C停。觉得终端刷屏不方便,可以改为写文件:
dlt-receive -o /home/logs/run.dlt -u
,后台运行它一段时间(或者放nohup、后台&让它一直记录)。若想从PC用GUI看,也可以在PC上跑dlt-viewer,通过SSH隧道把3490端口转发出来。比如:
ssh -L3490:localhost:3490 root@ecu
,然后本地dlt-viewer连127.0.0.1:3490即可。这在开发Adaptive时非常常用,因为很多ADAS ECU防火墙不直接开放3490,但可以ssh端口转发。另外DLT Viewer也支持SSH模式连接(自动建立隧道),如一些文档提及。最后恢复日志级别:
dlt-control -l 3 -a ADAS -u
把ADAS降回WARN,以免长期Verbose影响性能。
通过以上工具协同,即使没有图形界面,我们也能有效地控制和查看DLT日志。这对于自动化测试、CI中捕获错误日志,以及在现场仅有终端接入时诊断问题,都是十分方便的手段。
AUTOSAR Adaptive 与 Classic 的 DLT 差异与互通
AUTOSAR Adaptive 平台引入了与 Classic 平台不同的软件架构,DLT 机制也有所不同。本节比较 Classic vs Adaptive 在 DLT 功能上的差异,以及在车载混合环境中两者日志互通的策略。
Classic 平台 DLT 特点
前文已经详细介绍了Classic Platform(CP)的DLT实现。在此总结其关键特点:
静态配置为主:Classic DLT依赖 ECU 配置(ECU Configuration)预先定义所有Application ID、Context、LogChannel等。运行时很少有动态创建。上下文注册通常在Init阶段完成,新增上下文需要重配置代码。
BSW 模块实现:Classic DLT是一个标准BSW服务模块,运行在OS任务上下文中,和Com、PduR等一样受调度和优先级控制。它通过RTE接口与SW-C通信,通过PduR与网络通信,自己不涉及具体硬件细节。
通信方式:Classic DLT通过 ComStack(SoAd等)发送原始DLT消息。没有复杂的应用层协议。通常一ECU一个DLT端口,外部直接获取ECU原始日志。
开发适用:Classic DLT通常用于嵌入式ECU开发调试阶段,以及车厂端的黑盒测试阶段。在量产软件里DLT模块可以选择不编译或关闭(如果不需要远程日志)。因为其主要意义在开发诊断。
资源占用:Classic DLT占用ECU RAM(缓冲)、ROM(代码+静态配置)和少量CPU(格式化、转发)。对于中低端单片机ECU,这些资源有限,因此Classic DLT需要在调试完毕后通常禁用或精简(如关闭Verbose等)。BSW模块开销可通过生成配置调整,比如Buffer调小、不启用注入等优化。
Adaptive 平台 DLT 特点
Adaptive Platform(AP)的Log & Trace服务虽然名字相同,但架构和用法上有明显差别:
动态与服务化:Adaptive DLT并非作为BSW模块存在,而是作为Adaptive Services中的一员。典型实现如ara::log库和dlt-daemon进程组合。Adaptive应用通过C++ API (Logger类)使用日志服务。应用可以在运行时随时注册加入日志系统(比如一个新启动的Adaptive应用会向dlt-daemon注册其AppID)。
Logger API:Adaptive的日志接口更面向对象。例如
ara::log::Logger
提供LogError()
,LogWarn()
等方法,以及C++流式输出支持。开发者可方便地用logger.LogInfo() << "Value: " << x;
输出日志。内部会将内容封装成DLT消息格式。这比Classic的C宏更现代易用。模型化消息:Adaptive规范引入**模型化(Modelled)和非模型化(Unmodelled)**消息概念。模型化消息类似Classic的Non-Verbose,即预先在清单(Manifest)中定义好消息ID和参数结构,运行时只发送ID+参数。非模型化则像Verbose,发送完整字符串。Adaptive Logger API允许使用两者:开发者可以定义一些消息在Manifest中(类似Fibex),以节省带宽;其他用自由格式输出。Adaptive平台的通用原则是:为了高性能和低带宽占用,鼓励模型化消息。
配置方式:Adaptive系统使用**清单(Manifest)**来配置包括Log在内的各项服务。Machine Manifest里可以定义Log & Trace相关设置,如每个Application的默认LogLevel阈值、输出目标(比如写文件还是走DLT)等。Adaptive的日志可以灵活路由:既可以像Classic一样通过dlt-daemon网络输出,又可以配置写本地文件,或者输出到控制台。这取决于Manifest配置的后端(Backend)。通常在开发调试模式启用Console输出方便开发者即时看日志,在发布模式启用DLT后端供车厂调试。
dlt-daemon在AP:Adaptive系统一般跑POSIX OS,所以仍使用dlt-daemon。Adaptive各应用作为dlt-daemon的“本地客户端”注册。dlt-daemon发挥与Classic DLT类似的作用,只不过管理的是进程而非SW-C的context。外部看Adaptive ECU上的dlt-daemon,跟Classic ECU上的DLT模块提供的接口几乎一样,同为TCP3490服务。区别在于Adaptive一个ECU上可能跑多个ApplicationID各自输出,外部LogInfo会罗列多个进程的IDs。
可靠性:Adaptive可以借助底层OS特性,比如将关键日志写文件存储,当网络连接不稳定时稍后同步给后台。此外Adaptive的日志可以通过SOME/IP服务转发给其他ECU或云端,因为AP支持更复杂的通信。Classic则基本局限本地输出。
差异对比总结
特性 | Classic DLT (AUTOSAR CP) | Adaptive DLT (AUTOSAR AP) |
---|---|---|
集成方式 | BSW模块,通过RTE提供服务 | 用户态服务(dlt-daemon + lib), 应用进程调用API |
配置机制 | ECU静态配置,编译期生成 | Manifest动态配置,可运行时调整 |
应用注册 | 静态(配置或init注册),不支持动态模块 | 动态(应用启动时向daemon注册) |
接口用法 | C函数/宏 via RTE (Log, Trace, Control etc) | C++ Logger类 (LogDebug(), Logger<<) + dlt-control |
模式 | Verbose/Non-Verbose(需独立Fibex) | Unmodelled/Modelled(Manifest中定义消息模型) |
通信传输 | PduR -> SoAd/UDP/TCP | dlt-daemon通过TCP/UDP发送(也可写文件) |
上下文Context | 4字节AppID+4字节CtxID,由配置决定 | AppID可以更长(支持长名字),每进程有缺省Context,更多Context也可注册 |
控制命令处理 | DLT模块内部处理,通知SW-C | dlt-daemon分发给各应用的lib,由应用处理回调 |
注入支持 | Classic DLT支持SW-C Injection(需要配置) | Adaptive环境下一般不需要DLT层Injection,可直接用Method调用或RPC机制 |
性能/资源 | 占用MCU资源,要慎用(调试时用) | 运行在高算力OS平台,可常驻运行 |
ECU间互通 | 需外部网关汇聚 | 可通过dlt-viewer同时连多ECU or central server |
工具链 | GENIVI DLT Viewer/daemon/control通用 | 同样使用GENIVI工具 |
从上表可见,Adaptive的DLT更灵活强大,也更复杂,但两者协议层是兼容的。Adaptive输出的日志格式仍遵循AUTOSAR DLT Protocol v1。因此一个DLT Viewer实例可以同时连接Classic ECU和Adaptive ECU,统一显示日志。由于ECU ID不同,Viewer会分开列出,用户可对比调试。
互通策略
在一个同时包含Classic和Adaptive平台ECU的车载网络中,实现日志互通需要考虑:
统一工具:OEM和开发团队通常希望用一个DLT Viewer监控全车。幸运的是,只要各ECU的DLT配置正确,这完全可行。Classic ECU通过以太网/串口提供DLT服务,Adaptive ECU跑dlt-daemon提供服务。将所有ECU IP:3490连接到Viewer,就能看到全车日志。
ECUID唯一:务必确保每个ECU配置不同的ECU ID。Adaptive ECU的ECU ID可在dlt.conf里设置,Classic ECU在DltGeneral里配置。Viewer会将ECU ID作为区分源的主要依据。如果冲突,会合并显示导致混乱。
AppID上下文管理:Classic的AppID一般是SW-C短名(4字符),Adaptive的AppID通常是应用程序名,可以较长,比如"AdaptiveApp1"。GENIVI DLT协议在R22-11以后支持长ID。Viewer新版本能正确显示长AppID,但旧版可能截断。因此在混合场景下,尽量升级使用最新版DLT Viewer以避免兼容性问题。
描述文件整合:Classic ECU各自Fibex、Adaptive ECU manifest解析,各有不同文件。如果想集中解析全部Non-Verbose日志,可以合并Fibex:把所有ECU Frames放入一个XML,并在Frame上区分ECU Ref。Viewer好像不直接支持多ECU Fibex,需要按连接加载各自文件。因此建议按ECU分别加载其描述(Classic用Fibex, Adaptive用自带的ARXML if any)。对于Adaptive模型化消息,理论上也能导出Fibex类似文件提供Viewer解析(Adaptive tooling应该能输出Dlt Extract)。
集中采集:一些项目引入中央网关(可能跑Adaptive)来收集分布式ECU的日志,然后集中存储或转发。这时,经典ECU可能把DLT消息发送到网关而非直接给外部PC,Adaptive网关再统一上传。这样的互通需要在网关配置多个DLT输入通道对应多个ECU ID,并在输出时保留ECU区分信息(比如以不同Session或自定义头标明来源)。GENIVI DLT未直接支持多ECU聚合,但可由应用层封装。由于较少采用,这里不展开。
Adaptive与Classic交互:Adaptive应用可能通过 SOME/IP调接口与Classic ECU通信。为了调试此交互,双方各自日志需要对照分析。例如Adaptive调用某Classic服务失败,可能Classic DLT有ERROR而Adaptive DLT有对应trace。这种场景下,在Viewer上同时查看两端日志是最高效的。通过时间戳(Adaptive和Classic的时间基准未必同步,但可以人工对齐或根据通信延迟估计)可以关联事件。为简化分析,可确保Adaptive和Classic都启用全局时间同步(例如使用Ethernet NTP或StbM Time Sync),这样日志时间统一参考真实时间轴。
维护方面:Classic和Adaptive DLT配置分属不同工具链,但最终交给整车测试的应该是同时包含所有ECU描述的一个“日志配置包”。里面包括DLT Viewer版本要求、每个ECU的描述文件、连接方法等。这样测试团队才能正确使用。开发时Classic和Adaptive团队也应沟通ID和ECU命名,避免撞名。
总之,AUTOSAR Classic和Adaptive在DLT层面能够比较平滑地互通,毕竟Adaptive也是设计上与Classic保持了一致性,只是实现有所不同。对于开发者来说,最明显的区别在于使用接口(Classic通过RTE ports,Adaptive通过C++ Logger)。但对于使用DLT Viewer的调试工程师来说,他们可能几乎感觉不到哪个日志来自Classic ECU,哪个来自Adaptive ECU——格式和呈现方式都是统一的。这也体现了AUTOSAR标准化的价值:不论底层如何实现,调试和诊断过程可以采用统一的方法和工具,这对于日益复杂的车载分布系统而言,是巨大的便利。
附录
本附录提供一些补充资料,包括配置清单、常见问题解答等,以供快速参考。
配置清单与参数汇总
DLT 模块主要配置项(Classic Platform):
全局开关:DltDevErrorDetect(开发错误检测),DltVersionInfoApi(版本查询接口),DltGeneralRxDataPathSupport(外部控制支持),DltGeneralInjectionSupport(注入支持),DltGeneralNvRAMSupport(配置持久化)。这些选项影响模块功能集,应根据需求开启,默认尽量关闭非必要功能以节省资源。
默认设置:DltDefaultLogLevel(默认日志级别阈值),DltDefaultTraceStatus(默认Trace开关),DltDefaultLogChannelRef(默认输出通道)。它们作为未特例指定时的全局缺省。
Log Channel:DltLogChannelId,DltLogChannelBufferSize,DltLogChannelThreshold,DltLogChannelTraceStatusFlag,DltLogChannelTrafficShapingBandwidth,DLTTxPduRef。每个通道均需设置并关联一个Tx PDU。
SW-C Context:DltSwcSessionId(SW-C实例ID),DltSwcSupportLogLevelChangeNotification(级别变化通知使能),DltSwcApplicationId,DltSwcContextId(上下文标识)。每个Context可选赋值 DltLogLevelThreshold,DltTraceStatusAssignment,DltLogChannelAssignment 覆盖默认。
Rx/Tx PDU:DLTRxPduRef(接收PDU引用),DLTTxPduRef(发送PDU引用)。需与Com/PduR/SoAd配置的实际PDU相对应。
Protocol Header选项:DltProtocol 扩展头选项,如 With ECU ID,With Session ID,With Timestamp 等。Vector工具表现为checkbox让用户选择哪些字段包含在消息头。根据内存和需求决定启用哪些(ECU ID一般启用保证可区分,Session如单实例可不开启)。
NonVerboseMessages:用于启用自动MessageID生成功能。如使用Vector Davinci,可以在DLTNonVerboseMessage配置中包含需要生成ID的条目或让工具自动计算所有。输出的ID应在生成的Extract文件(Fibex)中体现。
PduR Binding:PduRBswModules 列表包含 DLT 模块;PduRRoutingPaths配置DLT的Tx和Rx路径;每个Path内Src/Dest Pdu Ref正确填写。
AUTOSAR Adaptive Log & Trace 配置要点(供对比):
- Machine Manifest内Log & Trace Service配置,如
<LoggingChannel type="NETWORK" IP="...:3490"/>
,<ApplicationLogMode defaultLevel="WARN"/>
等。 - Adaptive Application在其 Manifest定义需要的log contexts(Adaptive上通常按进程,不像Classic那样多Context,除非应用自己细分模块)。
典型故障及 FAQ
Q1: 为什么 DLT Viewer 连上ECU后没有日志输出?
A1: 可能原因:
- ECU端DLT模块未激活(需调用SetState开启)。请确认SW-C init是否调用了DLT_SetState(DLT_ON)。
- 日志级别阈值过高,当前没有高于阈值的日志触发。如默认OFF,则不会输出任何日志。可尝试通过dlt-control将DefaultLogLevel调低。
- PduR路由未正确配置,DLT消息未发送到通信接口。需检查PduR Routing Path配置,以及SoAd的Socket设置。
- 网络问题:ECU IP或端口不对,或防火墙阻挡。尝试ping ECU,或nc/telnet到3490端口测试连接。
- ECU端DLT缓冲满且未flush,导致新日志被丢弃。如果DLT任务挂起也可能如此。可复位ECU、降低日志频率再试。
Q2: Viewer中日志只显示Message ID和十六进制数据,没有可读文本?
A2: 这是Non-Verbose模式下未加载描述文件的表现。解决办法:获取正确的Fibex/ARXML描述文件并在Viewer中加载。加载后,之前的ID应转换为文本。如果已加载仍不解析,可能文件版本不匹配或ID冲突,需联系供应商确认Fibex正确性。
Q3: 日志内容在Viewer中乱码或错位,解析不正确怎么办?
A3: 可能描述文件定义与实际不符。例如参数类型不对、顺序不对。可以校验Fibex中的Frame定义和代码中的格式。特别是String类型,需要在Fibex中标明编码(SCOD字段)。如果是中文/Unicode字符,也需要Viewer和Fibex支持。另一个情况是时间戳看似乱码,其实因为Viewer未配置时间格式,可在Preferences调整时间显示。
Q4: DLT 日志对系统性能影响大吗?
A4: 在大量输出情况下,会有一定影响,主要是CPU格式化和通信占用。优化方法:
- 使用Non-Verbose模式,ECU端省去格式化打印开销,将大量静态内容移出运行时。
- 提高日志级别阈值,平时减少Debug/Info输出,只在必要时开启。
- 利用Traffic Shaping平滑数据流,避免瞬时占满总线。
- 将DLT任务设为低优先级,确保关键控制任务不被打断(已经是这样设计)。
- 实测中,在单片机上持续高频发送DLT会明显增加CPU负载,因此量产软件建议关闭冗余日志,仅保留关键错误。正确使用DLT不会对正常功能有明显干扰,但滥用Verbose可能拖慢系统,这是需要权衡的。
Q5: 如何保存DLT日志配置,使ECU重启后保留修改?
A5: 可以使用DLT的存储功能。如果配置了NvM支持,外部可以发送StoreConfiguration
控制命令。DLT模块会将当前的LogLevel/TraceStatus设置写入预先绑定的NvM块。下次ECU启动时DLT初始化会从NvM读取并应用这些设置,从而保留之前调整。例如,通过dlt-viewer勾选“Store Config”按钮或dlt-control加-o
选项即可触发。需要确保NvM块配置正确且在系统关机前有足够时间写入。
Q6: 多个ECU的日志如何区分分析?
A6: Viewer会依据ECU ID字段将不同ECU日志标记出来,可以在GUI中按ECU过滤。确保每个ECU的DLT配置用了不同的4字节ECUID(如ECU1, ECU2等)。这样Viewer日志列表中会有一列ECU名称标识来源。另外,也可在DLT Viewer中打开Connections窗口,对不同连接使用不同颜色高亮以示区分。总之,使用ECUID可以方便地区分日志来源ECU。
Q7: DLT 日志可以触发动作或报警吗?
A7: DLT Viewer本身提供Trigger功能,可以根据日志内容触发声音、弹窗或脚本。例如配置当收到包含"ERROR"的Fatal日志时,高亮并播放声音提示。这对于长时间测试时及时发现重要事件很有帮助。另外DLT日志也可以导出结合其他工具分析,如接入CAPL脚本或Python监视,发现特定模式发送CAN报文等。这些属于整车测试范畴的应用技巧。DLT作为载体,本身不直接触发ECU内部动作,但外部可以基于日志采取措施。
Q8: DLT 输出能否用于产品上继续保留?
A8: 可以,但要考虑资源和安全。部分厂商在量产版也保留DLT模块,以便售后排查车辆疑难杂症。这种情况下,一般会关闭Verbose和无关日志,仅打开Error级别的重要日志,并可能定期将日志写入车辆的数据记录仪(如中央网关NVRAM或远程服务器)。另外要防范隐私泄露,DLT日志中避免记录个人数据或过于详细的调试信息。GENIVI DLT支持Privacy Mask,如果标记某些日志为隐私则Viewer需有密钥才能解码,这在高级应用上可考虑。
Q9: 遇到DLT Daemon或Viewer版本兼容问题怎么办?
A9: 有时PC端Viewer版本过老,不能识别新规范字段(如长ID),或Adaptive的新dlt-daemon版本数据结构不同。尽量使用同一版本系列的dlt-daemon和dlt-viewer(例如都用2.18.x)。GENIVI(COVESA)社区会在文档中说明版本兼容性。如遇问题,可尝试升级Viewer。Viewer和daemon都是向下兼容为主,一般新版Viewer读取旧版daemon数据没问题,但旧Viewer读新版日志可能漏解析部分字段。升级是首选,若不能则在ECU端配置上避免使用新特性(如将长AppID截短等)。
Q10: 如何诊断DLT本身的故障?
A10: DLT模块很少故障,但如果怀疑DLT没工作,可以:
- 检查ECU CPU使用和内存,是否DLT任务挂死或缓冲溢出。
- 开启DltDevErrorDetect并通过调试接口看是否报DET错误。
- 在没有DLT输出时,尝试通过另一个调试口(如UART调试口)打印一些关键点看DLT函数返回值。例如SendLogMessage返回值不是E_OK,说明未成功,可能原因比如context未注册。
- 用PC抓包,看ECU是否根本没发数据,还是发了但Viewer未显示。前者多半ECU端问题,后者也许Viewer端未解析。
- 尝试使用dlt-control -j查询,如果连LogInfo都获取不到,则ECU端DLT很可能没运行或通信不通。若能获取List,但无日志输出,可能是没日志触发或过滤挡住。
- 最后,可在ECU上做DLT fallback方案:实现一个按键或测试信号,一旦触发就强制输出一条已知字符串的Verbose日志。如果Viewer依然收不到,则说明DLT通路有问题,需要检查PduR/SoAd等底层。如果收到了,则DLT正常,问题在上层日志没触发或被过滤。
通过以上FAQ,希望能解答实际使用AUTOSAR DLT过程中的常见疑问。DLT作为强大的日志工具,其配置和使用需要一定学习成本,但一旦掌握,能极大提高调试和诊断效率,真正实现“让数据自己会说话”。在遇到问题时,多参考本文以及AUTOSAR规范原文、GENIVI用户指南等,相信大部分疑难都可迎刃而解。祝各位工程师在AUTOSAR DLT的助力下,高效地开发出可靠的汽车电子系统!