目录
在前面 《[CP_AUTOSAR]_通信服务_CanTp模块(一)》 和 《[CP_AUTOSAR]_通信服务_CanTp模块(二)》 文章中介绍了CanTp 模块的主要功能、与其它模块的交互关系,以及功能规范。本文再接着介绍下CanTp 模块的其它功能规范。
3.3、内部行为
3.3.2、N-SDU Transmission
如之前文章中描述,上层通过 CanTp_Transmit() 函数来请求发送 N-SDU,函数的参数描述了待发送消息的CAN NSduId 和 Tx N-SDU 长度。
下表是关于 N- PDU 发送的一些功能需求描述:
需求 | 描述 |
---|---|
[SWS_CanTp_00225] | 对于那些不使用元数据的连接,函数 CanTp_Transmit 应该使用 SduLength 信息,而不使用 N-SDU 数据缓存,这样是为了准备单帧或者首帧的PCI。 |
[SWS_CanTp_00334] | 当为了发送带有元数据的 N -PDU去调用函数 CanTp_Transmit 时,CanTp 模块应该存储在 N-SDU 元数据中包含的地址信息,并用这个信息来发送单帧,首帧和连续帧 N - PDUs,在元数据中的地址信息依赖于地址格式: 1、Normal: none; 2、Extended: N_TA; 3、Mixed 11 bit: N_AE; 4、Normal fixed: N_SA, N_TA; 5、Mixed 29 bit: N_SA, N_TA, N_AE; |
[SWS_CanTp_00335] | 对于通用连接的SF,FF,CF去调用函数 CanTp_Transmit ,CanTp 模块应该通过 N - PDU的元数据提供存储的地址信息,这个地址信息依赖于以下地址格式: 1、Normal, Extended, Mixed 11 bit: none; 2、Normal fixed, Mixed 29 bit: N_SA, N_TA; |
[SWS_CanTp_00167] | 上层请求发送消息之后,在调用函数 PduR_CanTpCopyTxData 之前,CanTp 模块应该开始 N_Cs 超时计时,在时间消逝之前如果未获得数据,则中止通信 ; |
[SWS_CanTp_00086] | 发送SF/FF/CF,CanTp 模块应该调用 PduR_CanTpCopyTxData 服务,以便上层拷贝发送的数据到 PduInfoType 结构中; |
[SWS_CanTp_00272] | API 接口函数 PduR_CanTpCopyTxData()包含了一个参数 ’retry’,此参数用于恢复机制。而在 ISO 15765-2 规范中不支持这种恢复机制,因此此参数总是设置为空指针; |
[SWS_CanTp_00087] | 如果函数 PduR_CanTpCopyTxData() 返回值为 BUFREQ_E_NOT_OK,CanTp 模块应该终止发送请求,并回调 PduR_CanTpTxConfirmation() (函数返回值为 E_NOT_OK)去通知上层这个失效; 注意:如果上层暂时没有足够Tx缓存空间,函数 PduR_CanTpCopyTxData() 返回值为 BUFREQ_E_BUSY; |
[SWS_CanTp_00184] | 如果函数 PduR_CanTpCopyTxData() 返回值为 BUFREQ_E_BUSY,CanTp 模块应稍后重新尝试拷贝数据; |
[SWS_CanTp_00280] | 在 N_Cs 超时结束之后仍未获得数据,CanTp 模块应该通过回调 PduR_CanTpTxConfirmation() (函数返回值为 E_NOT_OK)去通知上层这个失效; |
[SWS_CanTp_00310] | 如果 N_As 超时发生,CanTp 模块应该通过回调 PduR_CanTpTxConfirmation() (函数返回值为 E_NOT_OK)去通知上层; |
[SWS_CanTp_00309] | 如果 FS 被设置为 OVFLW 的流控帧被接收,CanTp 模块应该终止发送请求,并通过回调 PduR_CanTpTxConfirmation() (函数返回值为 E_NOT_OK)去通知上层; |
[SWS_CanTp_00317] | 如果 无效FS 的流控帧被接收,CanTp 模块应该终止发送请求,并通过回调 PduR_CanTpTxConfirmation() (函数返回值为 E_NOT_OK)去通知上层; |
[SWS_CanTp_00315] | 在确认首帧发送、block 中的最后一个连续帧和显示 FS=WT 的流控帧,CanTp 模块应该对 N_Bs 进行时间观测; |
[SWS_CanTp_00316] | 如果 N_Bs 超时发生,CanTp 模块应该终止此消息的发送,并且通过回调 PduR_CanTpTxConfirmation() (函数返回值为 E_NOT_OK)去通知上层; |
[SWS_CanTp_00090] | 当发送会话成功完成时,CanTp 模块应该通过回调 PduR_CanTpTxConfirmation() (函数返回值为 E_OK)去通知上层; |
[SWS_CanTp_00343] | 在调用函数 CanIf_Transmit() 发送SF/FF/CF返回值为E_NOT_OK时,CanTp 模块应该终止当前发送连接; |
3.3.3、Buffer strategy
由于 CanTp模块没有缓存能力,所以要发送的N-SDU数据载荷不会在内部复制,收到的 N-PDU 也不会在内部重新组装。CanTp 层直接工作在上层模块(如PduR, DCM 和 COM)的内存区域中,为了访问这些内存区域,CanTp 层使用了 PduR_CanTpCopyTxData() 或者是 PduR_CanTpCopyRxData()的函数。因此,为了保护数据一致性,上层应该锁住内存区域直到传输完成。当内存区域被锁住时,上层不可能会写入数据到内存区域中。
下图是接收和发送缓存的锁状态:即发送过程中锁住内存区域,发送完成后,解锁内存区域;开始接收时锁住内存区域,完成接收时,解锁内存区域。
接收时调用函数 PduR_CanTpStartOfReception() 或者发送时调用 CanTp_Transmit(),上层模块应该保持内存区域的buffer锁住,直到接收完成(调用 PduR_CanTpRxIndication())或者发送完成(调用 PduR_CanTpTxConfirmation())发生。
下图就是一个例子,展示了发送一帧的过程,该帧长度为50个字节,使用CAN2.0协议。
1、PduR 请求发送一个50字节的数据;
2、CanTp 模块请求要传输的数据,并发送首帧;
3、CanTp 模块以序列化的连续帧发送剩余数据,每个连续帧中7个字节数据;
4、CanTp 模块调用 PduR_CanTpRxIndication() 确认传输数据的发送;
下图是接受一个49个字节的N - PDU的案例,上层汇报25个字节作为 Tx 缓存空间。
1、CanIf 模块使用 CanTp_RxIndication() 来通知 PduR 需要接受一个新的消息;
2、 PduR 模块返回缓存空间为25字节,CanTp 模块发送一个流控帧(状态为 CTS);
3、CanTp 模块提供每个接收到的帧数据给到 PduR 模块,并且检测剩余的缓存空间;在第二个连续帧传输之后,剩余空间剩余5个字节,不够容纳下一个 block (2个连续帧);
4、CanTp 模块调用 PduR_CanTpCopyRxData() 函数,函数入参数据长度为0,另外一个入参数据为空指针,并发出一条FS为等待状态的流控帧,知道有足够下一个block大小的空间;
5、当有足够下一个block大小的空间时,CanTp 发出一条FS为CTS状态的流控帧,并开始继续接收下一个连续帧 block ;
6、当接收到 block 中的最后一条连续帧,剩余的缓存空间又不足以容纳下一个 block ,因此,CanTp 再次发送FS为等待状态的流控帧,并检测剩余的缓存空间;
7、当缓存空间对最后一个 block 准备就绪时,CanTp 模块继续接收;
8、CanTp 模块调用 PduR_CanTpRxIndication() 函数通知 PduR 接收结束;
3.3.4、Protocol parameter setting services
需求 | 描述 |
---|---|
[SWS_CanTp_00091] | CanTp 模块应该支持一些传输层内部参数(STmin 和 BS)的动态设置。 |
3.3.5、Tx and Rx data flow
下图展示了单帧消息的发送过程:
下图展示了被分割消息的发送过程:
流控帧可以调整发送方来适应接收方的接收能力,
需求 | 描述 |
---|---|
[SWS_CanTp_00092] | CanTp 模块应该提供1对n的通信(即功能寻址)。 |
[SWS_CanTp_00093] | 如果多个被分割会话发生(在接收端和发送端),其句柄的通信类型是功能寻址,CanTp 模块应该拒绝这个请求,并向Default Error Tracer汇报运行时的错误代码 CanTp.CANTP_E_INVALID_TATYPE 。 |
3.3.6、Relationship between CAN NSduId and CAN LSduId
此部分描述了CAN NSduId 和 CAN LSduId之间存在的联系,
需求 | 描述 |
---|---|
[SWS_CanTp_00035] | CAN NSduId应该链接到一个 CAN LSduId,用于发送 SF / FF / FC 和 CF帧。 |
[SWS_CanTp_00281] | 如果消息被配置为扩展或者混合的地址模式, CanTp 模块应该填充每个发送部分(SF / FF / CF)第一个字节为 N_TA (扩展地址时)或者填充 N_AE (混合地址时)。因此, CAN NSduId 值与N_TA 或者 N_AE值有关。 |
[SWS_CanTp_00282] | FC PDUs 可以改变发送方发送的连续帧之间的延时。 |
[SWS_CanTp_00283] | 对于扩展地址格式,FC 的第一个数据字节包含了 N_TA值 或者是 N_TA 和 N_TAtype的唯一结合后的值。对于混合地址格式,FC 的第一个数据字节包含 N_AE值; |
[SWS_CanTp_0094] | 因此流控帧的CAN LSduId 与它的 N_TA值相结合(比如,N_AI),或者与 N_AE 值相结合,那么结合后的 CAN LSduId 只能够区分一个 CAN NSduId。 |
[SWS_CanTp_00284] | 在接收方向,每个(SF / FF / CF) PDU 的第一个字节值应该被用来去决定相关的 N-PDU 。 |
[SWS_CanTp_00095] | 因此,扩展地址接收N-PDU,CanTp 模块应该提取 N_TA 值,来构建出对应的N-PDU 。 |
下图描述了这些需求:
3.3.7、Concurrent connection
CanTp 层应该能够同时管理几个连接(比如同时接收 UDS 和 OBD的请求)。
需求 | 描述 |
---|---|
[SWS_CanTp_00096] | CanTp 模块应该同时支持几个连接 。 |
[SWS_CanTp_00120] | 在CanTp 模块中,可以配置同时连接 。 |
[SWS_CanTp_00285] | 外部无法访问连接通道,只能由 CanTp 模块内部访问 。 |
[SWS_CanTp_00286] | CanTp 层模块可以所有的参数(通道数量、时序参数)。 |
[SWS_CanTp_00121] | 每个 N - PDU静态链接到一个连接通道,其表示了接收和发送消息的内部路径,可以附着到一个或者多个N - PDU 。 |
[SWS_CanTp_00122] | 每个连接通道和其他的连接通道都是独立的,这意味着连接通道使用自己的资源,比如内部缓存,时序或者状态机。 |
[SWS_CanTp_00190] | CanTp 模块应该路由N-PDU到正确的连接通道 。 |
[SWS_CanTp_00287] | CanTp 模块不能并行接收同样ID的N-SDU,因为被接收的帧无法被分配给正确的通道 。 |
[SWS_CanTp_00288] | 如果一个连接通道被分配给多个 N - PDUs,那么资源就在N - PDUs中共享;如果没有空闲的连接通道,CanTp 模块会拒绝收发 。 |
[SWS_CanTp_00289] | 连接通道数不能直接配置,其取决于配置工具,取决于分析N-SDU/Channel 路由表 。 |
[SWS_CanTp_00123] | 如果配置的发送连接通道正在使用(CANTP_TX_PROCESSING),CanTp 模块应该拒绝新的发送请求链接到这个通道 。当上层使用函数 CanTp_Transmit() 请求发送消息时,CanTp 模块应该返回 E_NOT_OK。 |
[SWS_CanTp_00124] | 当接收到不带元数据的SF 或者 FF N-PDU时,并且对应的通道正在接收同样的连接(CANTP_TX_PROCESSING,相同的 N_AI),CanTp 模块应该停止正在接收中的接收,而开始处理新的接收帧。 当另外一个连接通道(不同的 N_AI)接收到不带元数据的SF 或者 FF N-PDU时,SF / FF应该被忽略。 |
[SWS_CanTp_00337] | 当接收到带元数据的SF 或者 FF N-PDU(表示通用连接)时,而相应的连接通道正在接收,SF / FF应该被忽略 。 |
[SWS_CanTp_00248] | 当一个Tx N-PDU 不同通道连接所使用时,应该使用TxConfirmation串行访问这个N-PDU。如果对该N-PDU使用扩展或混合寻址,或者当它具有元数据时,Rx N-PDU只能在两个或两个以上不同的连接通道上使用 。 |
3.3.8、N-PDU padding
所有的上层软件模块都会关注帧数据长度(比如OBD始终要求数据长度被设置为8字节,而UDS不是),为了保证这种兼容性,在预编译时期,对于 Rx N-SDU 使用 CanTpRxPaddingActivation ,对于 Tx N-SDU 使用CanTpTxPaddingActivation 去配置填充功能。
需求 | 描述 |
---|---|
[SWS_CanTp_00116] | CanTp 模块应该传输数据字节到上层,在填充和非填充模式下 。 |
[SWS_CanTp_00059] | 填充的字节值可以通过参数 CANTP_PADDING_BYTE 来配置 。 |
[SWS_CanTp_00344] | Rx N-SDU 帧字节数小于8字节,并且 CanTpRxPaddingActivation = CANTP_ON,CanTp 模块应该只能接收SF Rx N-PDUs 或者 最后一个 CF Rx NPDUs。 |
[SWS_CanTp_00345] | Rx N-SDU 帧字节数小于8字节,并且 CanTpRxPaddingActivation = CANTP_ON,CanTp 模块借助于回调函数 CanTp_RxIndication() 接收属于那个N-PDU的 SF Rx N-PDU,N-SDU 长度小于8字节,CanTp 模块应该拒绝接收。运行时,错误码 CanTp.CANTP_E_PADDING 应该汇报给Default Error Tracer。 |
[SWS_CanTp_00346] | Rx N-SDU 帧字节数小于8字节,并且 CanTpRxPaddingActivation = CANTP_ON,CanTp 模块借助于回调函数 CanTp_RxIndication() 接收属于那个N-PDU的最后一个 CF Rx N-PDU ,N-SDU 长度小于8字节,CanTp 模块应该回调 PduR_CanTpRxIndication() 函数(返回值为E_NOT_OK)丢弃正在进行中的接收,运行时,错误码 CanTp.CANTP_E_PADDING 应该汇报给Default Error Tracer。 |
[SWS_CanTp_00347] | Rx N-SDU的CanTpRxPaddingActivation = CANTP_ON, CanTp 模块应该发送 FC N-PDUs(长度为8字节),未使用的字节应该用CANTP_PADDING_BYTE 来填充 。 |
[SWS_CanTp_00348] | Tx N-SDU 帧数据载荷小于8字节,CanTpTxPaddingActivation = CANTP_ON,CanTp 模块应该借助于CanIf_Transmit() 函数来发送属于那个N-PDU的 SF Tx N-PDU 或者最后一个 CF Tx N-PDU ,字节长度为8字节,N-PDU 未使用的字节应该用CANTP_PADDING_BYTE 来填充 。 |
[SWS_CanTp_00349] | 借助于回调函数 CanTp_RxIndication() , Tx N-SDU 的 FC N-PDU被接收,且 CanTpTxPaddingActivation = CANTP_ON,且该FC 长度小于8字节。CanTp 模块通过回调 PduR_CanTpTxConfirmation() 函数(其返回值 E_NOT_OK)丢弃该传输会话,运行时,错误码 CanTp.CANTP_E_PADDING 应该汇报给Default Error Tracer。 |
[SWS_CanTp_00351] | CanIf_Transmit() 函数传输不符合DLC值(0…8, 12, 16, 20, 24, 32, 48, 64)数据长度的消息,CanTp 模块应该使用更高的DLC值用于传输,并且使用 CANTP_PADDING_BYTE 来初始化未使用的字节。 |
以下图片表示 ISO 帧:
3.3.9、Handling of unexpected N-PDU arrival
CanTp 模块对于非预期的 N-PDU 报文,很大程度上取决于N-PDU的通信方向。
需求 | 描述 |
---|---|
[SWS_CanTp_00057] | 如果接收到非预期帧,CanTp 模块应该根据下表作出对应的操作,表中内容根据CanTp 内部状态,指定了 N-PDU 处理方式。 |
接收到的 N-PDU 在传输或者发送中,包含了同样的地址信息(N_AI),在 N-PDU收到时,地址信息(N_AI)可能正在处理中。
下表是N-PDU报文到达时的处理方法:
状态 | SF | FF | CF | FC | Unknown N-PDU |
---|---|---|---|---|---|
Segmented Transmit in progress | 如果一个接收正在处理中,应根据以下单元处理,否则在开始接收时处理SF。 | 如果一个接收正在处理中,应根据以下单元处理,否则在开始接收时处理FF。 | 如果一个接收正在处理中,应根据以下单元处理,否则忽略它。 | 如果FS是等待状态,处理FC,否则忽略它; | Ignore |
Segmented Receive in progress | 终止当前接收,通过 indication 函数(返回值为 E_NOT_OK)汇报给上层,并开始接收新的SF; | 终止当前接收,通过 indication 函数(返回值为 E_NOT_OK)汇报给上层,并开始接收新的FF; | 正在进行的接收中处理CF,并执行相应的检测(比如SN号) | 如果传输正在处理中,应根据以上单元处理,否则忽略它 | Ignore |
Idle | 开始接收时处理SF | 开始接收时处理FF | Ignore | Ignore | Ignore |
3.4、Error Classification
本部分描述了 CanTp 模块是如何管理一些错误类别的,其可能会在基础软件生命周期内发生。
需求 | 描述 |
---|---|
[SWS_CanTp_00008] | 一旦错误或者异常发生了,CanTp 模块不能修改当前的模块状态,而是应该汇报错误事件。 |
[SWS_CanTp_00291] | 如果是产品问题,DEM 模块应该通过 FIM 执行相应的后处理(比如回调模块进行状态修改)。 |
3.4.1、Development Errors
[SWS_CanTp_00293]
错误类型 | 错误码 | 值 |
---|---|---|
API服务函数使用了错误的形参:当 CanTp 模块回调函数时使用了无效参数 | CANTP_E_PARAM_CONFIG | 0x01 |
API服务函数使用了错误的形参:当 CanTp 模块回调函数时使用了无效参数ID | CANTP_E_PARAM_ID | 0x02 |
API服务函数使用了空指针 | CANTP_E_PARAM_POINTER | 0x03 |
模块初始化失败 | CANTP_E_INIT_FAILED | 0x04 |
模块未初始化,调用了API函数 | CANTP_E_UNINIT | 0x20 |
无效的发送 PDU ID | CANTP_E_INVALID_TX_ID | 0x30 |
无效的接收 PDU ID | CANTP_E_INVALID_RX_ID | 0x40 |
3.4.2、Runtime Errors
[SWS_CanTp_00352]
错误类型 | 错误码 | 值 |
---|---|---|
接收到的 PUD 数据长度小于8字节 | CANTP_E_PADDING | 0x70 |
调用 CanTp_Transmit() 函数,使用功能寻址和长度参数来配置Tx I-PDU,则消息不能发送SF | CANTP_E_INVALID_TATYPE | 0x90 |
请求操作不支持:一个 N-PDU 取消了发送/接收的请求,但它并不在接收/发送过程中; | CANTP_E_OPER_NOT_SUPPORTED | 0xA0 |
在接收/发送中,如果是实现方面的错误而不是协议超时错误,应汇报错误事件 | CANTP_E_COM | 0xB0 |
在接收中,发生了协议超时错误,应汇报错误事件 | CANTP_E_RX_COM | 0xC0 |
在发送中,发生了协议超时错误,应汇报错误事件 | CANTP_E_TX_COM | 0xD0 |
[SWS_CanTp_00229]:
如果任务因为 As, Bs, Cs, Ar, Br, Cr 超时而停止了,CanTp 模块应该汇报开发实现层面的错误码 CanTp.CANTP_E_RX_COM (如果是接收过程)或者 CanTp.CANTP_E_TX_COM (如果是发送过程);如果任务因为其他协议层面错误而停止,CanTp 模块应该汇报运行时的错误码 CanTp.CANTP_E_COM 给 DET 模块。