CanIf发送逻辑CanIf_Transmit机制及CanIf发送配置解析

一.前言:
整个的autosar的can通信模块的层次如图:
通信模块可以大致分为三大功能:数据发送功能,数据接收功能,状态切换和管理功能。
我们的系列按照这样的功能排序和自底向上的模块排序,每次只介绍其中的一个模块的其中一个功能的实现,所以在每篇文章中对于模块不会事无巨细的介绍所有它所具备的功能,而是选择性的介绍三大功能中的其中一个。bsw往上的所有模块示例,为最大程度了解其设计思路以及避免侵权风险,将会采用遵循autosar架构的非商业代码作为示例,其部分细节不保证完全遵循autosar最新的标准,不保证所有功能的具备,敬请理解。
二.canif模块及其发送函数canif_transmit
在上节的文章中介绍了can模块的发送底层逻辑,can_write函数的介绍。can_write函数已经对can驱动进行了抽象。抽象为了hoh供上层使用。而它的上层就是canif层.在canif模块中,主要实现的功能如下:
1.传输请求(transmit request)
传输请求功能的实现主体函数是canif_transmit,这个函数内部调用can_write进行报文的发送
2.传输确认(transmit confirmation)
传输确认功能的实现主体函数是canif_txconfirmation,这个函数在can发送完成后被调用,作用是调用更上层的发送确认回调函数通知更上层的各个模块对应的pdu已发送成功。
3.接收提示(reception indication)
传输确认功能的实现主体函数是canif_rxindication,这个函数在can发送完成后被调用,作用是调用更上层的发送确认回调函数通知更上层的各个模块对应的pdu已发送成功。
4.can控制器模式切换(controller mode control)
controller模式切换的功能实现主体函数是canif_setcontrollermode,涉及到模式切换的功能后面专题详解
5.pdu模式切换(pdu mode control)
pdu模式切换的功能实现主体函数是canif_setpdumode,涉及到模式切换的功能后面专题详解
整个canif模块实现的基本函数如下:
本文侧重介绍canif模块的发送功能。canif的报文发送功能由canif_transmit函数实现,此函数原型如下:
std_returntype canif_transmit(pduidtype cantxpduid, const pduinfotype *pduinfoptr)此函数会调用mcal的can模块中的can_write函数进行报文的发送。在上节介绍can_write函数的时候,说过其传入的参数是以下:
hohcan id:报文idlength:报文长度sdu:报文数据swpduhandle :tx_confirm的id而canif层的传入参数变为了:
cantxpduid,pduinfoptr这个参数包括了sdudataptr和sdulength所以cantxpduid对can_write函数所需的hoh,can id,swpduhandle做了抽象。我们基本也可以推断出canif的txpdu所需要配置的主要内容了。
三.canif模块的发送配置解析
以下例子用于说明canif层的tx配置。
canif涉及到发送报文的主要配置结构体如下:
const canif_initconfigtype canifinitconfig ={ .canifconfigset = 0, .canifnumberofcanrxpduids = sizeof(canifrxpduconfigdata)/sizeof(canif_rxpduconfigtype), .canifnumberofcantxpduids = sizeof(caniftxpduconfigdata)/sizeof(canif_txpduconfigtype), .canifnumberofdynamiccantxpduids = 0, // containers .canifhohconfigptr = canifhohconfigdata, .canifrxpduconfigptr = canifrxpduconfigdata, .caniftxpduconfigptr = caniftxpduconfigdata,};我们以下主要关注:
1.hoh的配置结构体canifhohconfigdata,
2.发送pdu配置结构体caniftxpduconfigdata
1.hoh的配置结构体canifhohconfigdata,
对于hoh的配置结构体canifhohconfigdata的结构如下:
const canif_inithohconfigtype canifhohconfigdata[] = { { #if(canif_control_can_driver ==std_on) .canconfigset = &canconfigsetdata, #endif .canifhrhconfig = canifhrhconfigdata_hoh_1, .canifhthconfig = canifhthconfigdata_hoh_1, },};其中配置了发送的hth和接收的hrh。对于发送的hth配置如下:
const canif_hthconfigtype canifhthconfigdata_hoh_1[] ={ { .canifhthtype = can_basic, .canifcancontrolleridref = canif_channel_1, .canifhthidsymref = hoh_3_udstx_node, }, { .canifhthtype = can_basic, .canifcancontrolleridref = canif_channel_1, .canifhthidsymref = hoh_3_nmtx_node, }, { .canifhthtype = can_basic, .canifcancontrolleridref = canif_channel_1, .canifhthidsymref = hoh_3_xcptx_node, }, { .canifhthtype = can_basic, .canifcancontrolleridref = canif_channel_1, .canifhthidsymref = hoh_3_ecutestnode_cancluster, },};主要就是引用了上节文章例子中介绍的can模块配置的四个hoh。
2.发送pdu配置结构体数组caniftxpduconfigdata
这个结构体数组有所有的发送pdu配置,每个pdu都是一个结构体成员,其中的一个成员配置示例如下:
const canif_txpduconfigtype caniftxpduconfigdata[] = { { .caniftxconfrimpduid = cantp_pdu_id_uds_phys_tx, .canifcantxpduidcanid = 0x7ea, .canifcantxpduiddlc = 8, .canifcantxpdutype = canif_pdu_type_static,#if ( canif_readtxpdu_notify_status_api == std_on ) .canifreadtxpdunotifystatus = false,#endif .caniftxpduidcanidtype = canif_can_id_type_11, .canifusertxconfirmation = cantp_txconfirmation, .canifcantxpduhthref = &canifhthconfigdata_hoh_1[0], .pduidref = null, }, ..... }关键的参数解释如下:
caniftxconfrimpduid :用于为swpduhandle 复值,向对应的txconfirm函数传入参数。canifcantxpduidcanid:对应pdu的报文idcanifcantxpduiddlc:对应pdu的报文长度canifusertxconfirmation:发送确认回调函数canifcantxpduhthref:发送此pdu要使用的hoh类似上节的结尾说到的抽象。这些配置元素打包成一个结构体数组元素,
canif_transmit需要传入的cantxpduid,即代表这个配置结构体数组的数组下标。用来索引到其抽象的对象属性。说起来比较枯燥,以下是canif_transmit的实现函数:
std_returntype canif_transmit(pduidtype cantxpduid, const pduinfotype *pduinfoptr){ can_pdutype canpdu; const canif_txpduconfigtype *txentry; canif_controllermodetype csmode; canif_channelgetmodetype pdumode; validate(canif_global.initrun, canif_transmit_id, canif_e_uninit ); validate((pduinfoptr != 0), canif_transmit_id, canif_e_param_pointer ); // get the controller from l-pdu handle txentry = canif_findtxpduentry(cantxpduid); if (txentry == 0) { validate(false, canif_transmit_id, canif_e_invalid_txpduid); return e_not_ok; } canif_arc_channelidtype channel = txentry- >canifcantxpduhthref- >canifcancontrolleridref; // get and verify the controller mode if (canif_getcontrollermode(channel, &csmode) == e_not_ok){ return e_not_ok; } if (csmode != canif_cs_started){ // canif_161 return e_not_ok; } // get and verify the pdu channel mode control if (canif_getpdumode(channel, &pdumode) == e_not_ok){ return e_not_ok; } if ((pdumode != canif_get_tx_online) && (pdumode != canif_get_online)){ return e_not_ok; } canpdu.id = txentry- >canifcantxpduidcanid; canpdu.length = pduinfoptr- >sdulength; canpdu.sdu = pduinfoptr- >sdudataptr; canpdu.swpduhandle = cantxpduid; can_returntype rval = can_write(txentry- >canifcantxpduhthref- >canifhthidsymref, &canpdu); if (rval == can_not_ok){ return e_not_ok; } if (rval == can_busy) // canif 082, canif 161 { // tx buffering not supported so just return. return e_not_ok; } return e_ok;}注意到其中canif_transmit的传入参数cantxpduid的使用方式:
txentry = canif_findtxpduentry(cantxpduid);
canif_findtxpduentry的函数原型如下
static const canif_txpduconfigtype * canif_findtxpduentry(pduidtype id){ if (id >= canif_configptr- >initconfig- >canifnumberofcantxpduids) { return null; } else { return &canif_configptr- >initconfig- >caniftxpduconfigptr[id]; }}就是以canif_transmit的传入参数cantxpduid为下标,找到对应的caniftxpduconfigdata的数组成员。并获取其属性,对can_write函数的传入参数进行配置。调用can_write函数进行发送。
四.发送确认函数:canif_txconfirmation
canif_txconfirmation是由can模块底层驱动在pdu传输完成后调用的。之前讲到can_write函数的其中一个传入参数:swpduhandle是用来在底层标记传输的pdu id,在更新messagebuffer前记住pdu对应的swpduhandle参数,在对应的pdu发出去后,底层驱动函数调用canif_txconfirmation传入swpduhandle。
而我们的canif_txconfirmation实现如下:
void canif_txconfirmation(pduidtype cantxpduid){ validate_no_rv(canif_global.initrun, canif_txconfirmation_id, canif_e_uninit) validate_no_rv(cantxpduid initconfig- >canifnumberofcantxpduids, canif_txconfirmation_id, canif_e_param_lpdu); const canif_txpduconfigtype* entry = &canif_configptr- >initconfig- >caniftxpduconfigptr[cantxpduid]; if (entry- >canifusertxconfirmation != null) { canif_channelgetmodetype mode; canif_getpdumode(entry- >canifcantxpduhthref- >canifcancontrolleridref, &mode); if ((mode == canif_get_tx_online) || (mode == canif_get_online) || (mode == canif_get_offline_active) || (mode == canif_get_offline_active_rx_online) ) { entry- >canifusertxconfirmation(entry- >caniftxpduid); /* canif053 */ } } return;}在这个函数中,会直接向上文caniftxpduconfigdata配置的canifusertxconfirmation中传入swpduhandle。
而在canif_transmit中,swpduhandle又是由caniftxpduconfigdata配置的caniftxconfrimpduid决定的。所以caniftxconfrimpduid会作为参数传入对应的canifusertxconfirmation。
这期的介绍就到这,本期介绍了canif主要实现的功能,主要函数,主要的发送配置以及canif_transmit,canif_txconfirmation的机制,可以了解canif做了更进一步的抽象,将hoh进一步抽象为了pdu。各个autosar架构的代码实现并不一致,文中所有的函数实现和配置思路仅作参考。

管道流量计的安装说明
关于推动移动出行未来的介绍和应用分析
如何防止数字货币交易所的资产被盗
九种经常被忽视的ADC规格
800V电动汽车开发:如何选好“料”,烹小鲜?
CanIf发送逻辑CanIf_Transmit机制及CanIf发送配置解析
超声波Theremin的制作教程
众耳难调也能一应俱全,华为FreeBuds 4降噪耳机固件升级让听感再升级
LiKEY LiFi -未来的超安全门禁控制解决方案
微电网系统-需量控制:能量储存、充放电功率跟踪 Acrelsale1
网络安全威胁频出,网络安全需得到大家重视
特斯拉将在国内推第三代家用充电桩
京东方需要新的利好消息,华为mate20证明京东方面板技术优秀
动力电池进入高速发展期 2024年全球动力电池市场将迈进TWh
移动护理PDA的特点及优势
如何设置Linux进程的睡眠和唤醒
一种构建面内p-n-p同质结降低石墨烯光电探测器暗电流的有效途径
韩国第一台户外外卖机器人正式运营
双温双控直冷式电冰箱电路图
AMD扩展低功耗G系列处理器产品阵容