随着当代汽车电子系统日益复杂,对其软件和系统架构提出了更高的要求。过去汽车电子系统采用 federated architectures,不同功能由分散的 ECU(电子控制单元)实现,各 ECU 之间独立运行,软件高度定制化。这使得整车功能的开发非常复杂,软件可重用性差,且不利于新功能的加入。为实现软件的可重用性和可移植性,AUTOSAR(汽车开放系统架构)应运而生。AUTOSAR 定义了基于分层模型的标准软件架构,明确规定了各层次的功能边界。这样有利于软件模块的解耦,也使供应链中的不同参与方能基于统一架构进行开发和集成。在 AUTOSAR 架构中,通信协议栈发挥着连接应用层软件和底层网络及硬件的关键作用。它实现了对底层网络的访问和配置,支持应用软件对信号和消息的发送接收。通信协议栈包含了 transport protocol、network access 和 device driver 等模块。为了实现模块之间和不同供应商产品之间的互操作性,AUTOSAR 规范详细定义了通信协议栈涉及的接口和数据类型。本文将深入解析 AUTOSAR 规范中通信协议栈类型定义的全部要求和设计思想。在复杂的分布式汽车电子系统中,通信协议栈的类型定义需要解决以下问题:- 如何设计通信协议栈各层级中关键数据类型,比如标识符、长度字段等?
- 不同供应商的上层应用软件和底层网络如何基于类型定义实现无缝集成?
本节详细解释 AUTOSAR 规范文件中定义的通信协议栈核心数据类型。这些类型抽象了通信协议栈处理的基本数据,并给出了详细注释说明用途和要求。PduIdType 用于唯一标识一个协议数据单元(PDU)。PDU 是通信协议栈中的基本信息单元,表示应用层交付的服务数据单元(SDU)加上协议控制信息的总体,可在不同层之间传递。typedef uint16 PduIdType;
PduIdType 建议配置为 16 比特无符号整数(uint16)(也可以是 uint8),以支持软件模块中最大数目的 PDU。每个模块都定义自己的 PduId 类型,用于在该模块内部索引和引用 PDU。- 每个软件模块中,PduId 的取值限定在 0 到 PduIdMax 之间。PduIdMax 等于给定模块需要处理的最大 PDU 编号。
- 对不同的模块,允许 PduId 定义不同的取值范围。这为模块解耦提供可能。
以 CAN TP(传输协议)模块为例,若它需要处理 20 个不同的 PDU,则可以定义:typedef uint16 CanTp_PduIdType;
#define CanTp_PduIdMax 19
这样就可以方便 CAN TP 内部使用 PduIdType 索引数组实现不同 PDU 的处理。同时,其它模块引用 CAN TP 的 PDU 时,也可以通过 PduIdType 作为统一接口,无需了解 CAN TP 内部的实现机制。这实现了模块的解耦。PduLengthType 定义一个 PDU 的数据长度信息,通常实现为无符号短整型(uint16,uint32,uint8): typedef uint16 PduLengthType;
其取值表示 PDU 的数据长度,单位为字节。配置为 16 比特无符号数可以支持最大长度为 64K 字节的 PDU。PduLengthType 需要满足:- 通过配置 PduLengthMax 来表示对应 ECU 可支持的最大 PDU 长度
如果没有使用数据分段,则最大数据长度由底层通信系统的帧长度决定。对于 FlexRay,最大帧负载为 255 字节,则可配置:
如果使用了分段传输,则需要根据最大分段长度 N-PDU,一般使用 uint16。PduInfoType 用于存储一个 PDU 的完整信息,包括:struct PduInfoType
{
uint8* SduDataPtr;
uint8* MetaDataPtr;
PduLengthType SduLength;
};
这样就将一个 PDU 的三部分关键信息封装到一个结构体中。- SduDataPtr:指向 PDU 中包含的服务数据单元,即实际应用层的数据
- MetaDataPtr:指向 PDU 的元数据,用于存储 PDU 控制信息,比如消息 ID 等
PduInfoType 提供了一个传递 PDU 信息的统一接口,可大大简化模块间的数据交换。例如,传输层模块和服务层模块之间,就可以直接共享 PduInfoType 对象,而不需要了解对方的具体实现。此外,AUTOSAR 通信协议栈类型定义中还包括其他各种数据类型:枚举,指定需要更改值的参数(BS 或 STmin)uint16,用于 Com 和 LdCom 用户回调的句柄 Ids例如,BufReq_ReturnType 包括以下枚举值:enum BufReq_ReturnType
{
BUFREQ_OK,
BUFREQ_E_NOT_OK,
BUFREQ_E_BUSY,
BUFREQ_E_OVFL
}
这些类型的命名和定义风格保持高度一致性,并统一通过 ComStack_Types.h 头文件对外提供,为上层应用提供复用和解耦的可能。为确保通信协议栈类型定义的正确性和一致性,AUTOSAR 规范对其提出了一些关键要求:- 定制化生成:类型定义会根据不同的 ECU 配置进行定制化生成,以适应不同需求
- 全局一致:所有定义必须完全一致,不允许未经许可修改或扩展
此外,AUTOSAR 通信服务要求类型定义仅包含数据本身,不包括任何功能实现。这保证了类型定义与具体实现的解耦。只要遵循上述要求和设计思路,就可以构建出可重用、可移植的通信协议栈类型。这些要求也有利于不同供应商基于标准类型进行开发和集成。标准化的类型定义有利于通信协议栈不同模块之间以及与应用软件之间建立统一的接口,实现无缝集成。以传输层模块(TP)为例,它就可以通过标准类型与服务访问点(COM)模块进行数据交换,而无需了解对方的内部实现逻辑。
void Tp_Transmit(PduIdType pduId, PduInfoType* pduInfo);
PduInfoType rxPdu;Tp_Transmit(pduId, &rxPdu);
这里 Tp_Transmit 通过输入参数 pduId 获取待发送的 PDU,并获取其 PduInfoType 信息。COM 模块利用同样的 PduInfoType 提供接收的 PDU。两者间利用同一类型定义实现了良好的隔离。如果没有这种标准接口,则 TP 和 COM 内部的实现紧密耦合,不利于维护和扩展。而统一的类型定义正是实现解耦的基础。