关于Linux中socket can怎么使用,CSDN上已经有很多文章介绍。本文重点记录can_filter中的 CAN_INV_FILTER的使用,很多文章对此一笔带过,且很多文章翻译不全,或者原文不全,导致自己浪费了些时间,最后在看candump源码时才发现问题所在。
直接贴代码解释,以下为写的一个最简单的canId过滤函数:
宏定义
/** CAN报文过滤方式 **/
#define CAN_FILTER_PASS 0x01 //过滤方式-通过
#define CAN_FILTER_REJECT 0x02 //过滤方式-拒绝
函数声明
/**
* @brief canRcvFiltersSet - CAN报文接收过滤设置
* @param canIdArray: 数组中每个元素为要过滤的canId且不能为0;若该参数置为NULL,则表示该Can口不需要接收任何报文
* @param arraySize: 数组大小,若canIdArray置为NULL,则该项置0
* @param filterType: 过滤方式的宏定义,若canIdArray置为NULL,则该项置0,否则应为以下二选一
* CAN_FILTER_PASS: 只接收与canIdArray中canId一致的报文
* CAN_FILTER_REJECT: 与canIdArray中canId一致的报文都不接收,其它报文接收
* @return true:成功,false:失败
*/
bool canRcvFiltersSet(const uint *canIdArray, const uint &arraySize, short filterType);
函数定义
bool rcvFiltersSet(const uint *canIdArray, const uint &arraySize, short filterType)
{
if(canfd <= 0) //canfd就不用解释了…
return false;
if(NULL == canIdArray){
setsockopt(canfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); //不需要接收任何报文
return true;
}
struct can_filter rfilter[arraySize];
bzero(rfilter,sizeof (rfilter));
for(uint i = 0; i < arraySize; ++i){
if(canIdArray[i]){
if(filterType & CAN_FILTER_PASS){
rfilter[i].can_id = canIdArray[i];
}
else{
rfilter[i].can_id = (canIdArray[i] | CAN_INV_FILTER);
}
rfilter[i].can_mask = CAN_EFF_MASK; //这个掩码怎么设置看自己需求
}else{
return false;
}
}
//重点!!!很多文章没提到这一点,过滤器反转时需要设置,使各过滤器之间由逻辑或变成逻辑与关系,
//否则设置的反转过滤器因为相互矛盾导致不起作用
//简单举例解释,过滤器A接收除0x123之外的报文,过滤器B接收除0x124之外的报文,
//那么0x123虽然被过滤器A过滤了,但是会被过滤器B通过,同理0x124会被过滤器A通过,所以实际上不起作用
//下面的设置就是让过滤器之间join起来,只有符合所有过滤器的规则才会被通过
if(filterType & CAN_FILTER_REJECT){
int join_filter = 1;
setsockopt(canfd, SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS, &join_filter, sizeof(join_filter));
}
setsockopt(canfd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
return true;
}
使用示例:
* const uint can_id_reject[] = {0x123, 0x11111678, 0x282}; //除这三种canid之外的报文,都接收
canRcvFiltersSet(can_id_reject, sizeof(can_id_reject)/sizeof(uint), CAN_FILTER_REJECT);
* const uint can_id_pass[] = {0x123, 0x11111678, 0x282}; //只接收这三种canid报文,其它不接收
canRcvFiltersSet(can_id_pass, sizeof(can_id_pass)/sizeof(uint), CAN_FILTER_PASS);
完。