Android CAN
kerel
- 默认编译成模块,没编译进内核
│ Symbol: CAN [=m] │
│ Type : tristate │
│ Prompt: CAN bus subsystem support │
│ Location: │
│ (1) -> Networking support (NET [=y]) │
│ Defined at net/can/Kconfig:5 │
│ Depends on: NET [=y]
- 在kernel/msm-4.9/arch/arm64/configs/msm8953_defconfig,添加CONFIG_CAN=y
socket
- 使用socket通信,有点像UDP(创建socket,bind地址,write,read)
- 使用原始套接字(SOCK_ROW),发送数据帧
- 可使用数组,一次性发送多个数据帧
- socket读写的是CAN总线,而不是另一个socket
数据帧格式
struct can_frame {
canid_t can_id;// CAN 标识符
__u8 can_dlc; // 数据场的长度
__u8 data[8]; // 数据
};
// can_id 为帧的标识符, 如果发出的是标准帧, 就使用 can_id 的低 11 位; 如果为扩展帧, 就使用 0~ 28 位。 can_id 的第 29、 30、 31 位是帧的标志位,用来定义帧的类型,定义如下:
// #define CAN_EFF_FLAG 0x80000000U //扩展帧的标识
// #define CAN_RTR_FLAG 0x40000000U //远程帧的标识
// #define CAN_ERR_FLAG 0x20000000U //错误帧的标识
过滤
- 通过错误掩码可以实现对错误帧的过滤
can_err_mask_t err_mask = ( CAN_ERR_TX_TIMEOUT | CAN_ERR_BUSOFF );
setsockopt(fd, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, err_mask, sizeof(err_mask));
- 过滤不需要的数据帧
struct can_filter rfilter[1]; // 定义接收规则,只接收表示符等于 0x11 的报文
rfilter[0].can_id = 0x11;
rfilter[0].can_mask = CAN_SFF_MASK;
// 设置过滤规则
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
自发自收
int loopback = 0; // 0 表示关闭, 1 表示开启( 默认)
setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
查看网卡
struct ifconf ifconf;
ioctl(fd, SIOCGIFCONF, &ifconf); // 获取所有接口信息
指定CAN总线
// 以下是对CAN接口进行初始化,如设置CAN接口名,即当我们用ifconfig命令时显示的名字
strcpy((char *)(ifr.ifr_name), "can0"); // 指定网卡名称
if (-1 == ioctl(fd, SIOCGIFINDEX, &ifr))
{ //获取网络接口
close(fd);
return -1;
}
注意
- 指定CAN总线失败,仍然可以发送接收,因为默认是使用lo(即127.0.0.1)
命令行工具
ifconfig can0 # 查询
ifconfig can0 up # 使能can0
ifconfig can0 down # 失能can0
sudo apt-get install can-utils # 安装
ip link set can0 down # 关闭
ip link set can0 type cantq 125 prop-seg 6phase-seg1 7 phase-seg2 2 sjw 1 # 配置 CAN 总线的位速率
ip link set can0 type can bitrate 125000 # 直接设定位速率
ip -details link show can0 # 查询 can0 设备的参数设置
ip -details -statistics link show can0 # 工作状态
测试
使用127.0.0.1收发正常,还没真正使用CAN