我们了解了CAN通信协议的基本原理后,让后就可以去考虑,Android代码怎么实现CAN通信了,如果不了解,请移步
车载Android开发的秘密--搞懂CAN通信 Android代码的实现,其实相对于来说还是很简单的。因为Linux的SocketCAN 我们可以直接拿来用了,我们这里就不分析Linux的源码了。。就分析Android显示层,到NDK调用Linux的SocketCan,如果有想要深入了解的同学,可以去下载NDK源码,去看一看,或者去下载SocketCAN的源码。话不多说进入正题。 这篇文章是基于3568的芯片,解析的。
1、打开CAN,设置波特率
打开3568的CAN口,我们是使用的,ProcessBuilder,ProcessBuilder是Java中的一个类,是用于管理外部进程的一个工具类,可以用来执行Shell命令。
ProcessBuilder processBuilder = new ProcessBuilder("su");
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
process.getOutputStream().write(" ip link set can0 down\n".getBytes());
process.getOutputStream().write("ip link set can0 type can bitrate 500000 dbitrate 500000 fd on\n".getBytes());
process.getOutputStream().write(" ip link set can0 up\n".getBytes());
process.getOutputStream().flush();
su的权限,是root权限,如果没有root权限,是用不了的,所以你的开发板先root。
无论CAN口是什么状态,先关闭,在开启,先down 后up。
2、openSocketCan,去打开Socket
因为是Linux的SocketCan,所以我们用NDK去打开。 domain:协议族(Protocol Family)。PF_CAN 表示使用 CAN 协议族。 type:套接字类型。SOCK_RAW 表示创建一个原始套接字,可以直接访问底层网络协议。 protocol:协议类型。CAN_RAW 表示使用 CAN 的原始协议
int fd;
struct ifreq ifr;
struct sockaddr_can addr;
/* open socket */
if ((fd = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
return -1;
}
const char *str = env->GetStringUTFChars(canx, 0);
strcpy(ifr.ifr_name, str);
ioctl(fd, SIOCGIFINDEX, &ifr);
memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
return -2;
}
return fd;
3、打开了Socket 就可以去读取和发送数据了,同样,我们使用NDK去操作
使用Socket 去读数据
jlongArray ret;
ret = env->NewLongArray(12);
struct can_frame frame;
read(fd, &frame, sizeof(struct can_frame));
int64_t data[12];
data[0] = frame.can_id & 0x1FFFFFFF;
data[1] = (frame.can_id >> 31) & 0x1;
data[2] = (frame.can_id >> 30) & 0x1;
data[3] = frame.can_dlc;
for(uint8_t i = 0; i < frame.can_dlc; i++) {
data[i + 4] = frame.data[i];
}
env->SetLongArrayRegion(ret, 0, 12, data);
return ret;
使用Socket 去写数据
struct can_frame frame;
frame.can_id = (eff << 31) | (rtr << 30) | canid;
frame.can_dlc = len;
jint *pdata = env->GetIntArrayElements(data, 0);
for(uint8_t i = 0; i < len; i++) {
frame.data[i] = pdata[i] & 0xFF;
}
int ret = write(fd, &frame, sizeof(struct can_frame));
env->ReleaseIntArrayElements(data, pdata, 0);
return ret;
这样看起来,还是蛮简单的。
4、NDK里关于CAN是直接封装了的,如果给写好了,那我们直接拿去用就好了,,哈哈
can.h在 ndk 下边的linux 的根目录,然后linux目录下边还有个can目录。
相比于串口来说,我们中间多了一个,Socket层。串口是直接读取文件句柄,读取缓冲区,就可以了。CAN通信的实现,也不用我们去使用第三方的框架, 我们直接使用NDK里的工具进行开发即可。
5、总结
CAN通信Android的实现,就到这里了,希望对兄弟们有用。以后再也不用为CAN而困扰。还有可能就是对C和C++不太熟悉,不过没关系,多写写就好了。兄弟们加油。