由于工作需要,将linux中的can通讯编写到Qt上,通过图形界面的方式演示出来。
CAN的初始化
int can::startCan(QString baud)
{
int ret = 0;
ret = system("ifconfig can0 down");
if (ret != 0)
{
return -1;
}
ret = system(QString("ip link set can0 up type can bitrate %1").arg(baul).toLatin1());
if (ret != 0)
{
return -1;
}
ret = system("ifconfig can0 up");
if (ret != 0)
{
return -1;
}
//创建套接字
//PF_CAN 为域位 同网络编程中的AF_INET 即ipv4协议
//SOCK_RAW使用的协议类型 SOCK_RAW表示原始套接字 报文头由自己创建
//CAN_RAW为使用的具体协议 为can总线协议
socket = ::socket(PF_CAN,SOCK_RAW,CAN_RAW);//创建套接字
if (socket<0)
{
qDebug()<<"[error]: socket\n";
return -1;
}
struct ifreq ifr;//接口请求结构体
strcpy((char *)(ifr.ifr_name),"can0");//判断开启的是can0/1
fcntl(socket, F_SETFL, 0);
ioctl(socket, SIOCGIFINDEX, &ifr);//指定 CAN0设备
addr.can_family = AF_CAN;//协议类型
addr.can_ifindex = ifr.ifr_ifindex;//can总线外设的具体索引 类似 ip地址
ret = bind(socket,(struct sockaddr*)&addr,sizeof(addr));//将套接字和canbus外设进行绑定,即套接字与 can0 绑定
if(ret<0)
{
qDebug()<<"[error]: can bind fail #"<<ret;
return -1;
}
return 0;
}
CAN接收
接收这里 要 注意的是,需要用到线程去接收,一开始我只是使用定时器去监控,就会出现当把can开启后,这个界面就会很卡顿,如果使用线程thread就可以解决这个问题。
int can::canrecv( struct can_frame *frame, uint32_t timeout_ms)
{
int ret,nbytes;
struct timeval tv;
struct msghdr msg;
struct iovec iov;
struct can_frame frame;
fd_set rdfs;
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3*sizeof(struct timespec) + sizeof(__u32))];
//poll mode
tv.tv_sec=timeout_ms/1000;
tv.tv_usec=(timeout_ms % 1000)*1000;
FD_ZERO(&rdfs);
FD_SET(socket, &rdfs);
ret=select(socket+1, &rdfs, NULL, NULL, &tv);
if(ret==0) { //timeout
return 0;
}
else if(ret<0) { //error
return ret;
}
nbytes = read(socket, &frame, sizeof(frame)); //接收报文
if(nbytes > 0)
{
QByteArray array;
for (int i = 0; i < frame.can_dlc; i++)
{
array[i] = frame.data[i];
}
}
return nbytes;
}
can发送
int can::cansend( uint16_t id, uint8_t *buf, uint8_t len)
{
int i;
int ret;
struct can_frame frame;
int size = sizeof(frame);
if(socket < 0)
{
return -1;
}
frame.can_id = id;
for(i=0; i<len; i++)
{
frame.data[i] = buf[i];
qDebug()<<frame.data[i];
}
frame.can_dlc = len;
qDebug()<<socket<<frame.can_dlc<< frame.can_id<<size;
ret = write(socket, &frame, size);
if (ret != size) {
qDebug()<<"ret="<<ret;
return -1;
}
return len;
}
相关结构体
struct ifreq
{
# define IFHWADDRLEN 6
# define IFNAMSIZ IF_NAMESIZE
union
{
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */
} ifr_ifrn;
union
{
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short int ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
__caddr_t ifru_data;
} ifr_ifru;
};
/**
* struct sockaddr_can - the sockaddr structure for CAN sockets
* @can_family: address family number AF_CAN.
* @can_ifindex: CAN network interface index.
* @can_addr: protocol specific address information
*/
struct sockaddr_can {
__kernel_sa_family_t can_family;
int can_ifindex;
union {
/* transport protocol class address information (e.g. ISOTP) */
struct { canid_t rx_id, tx_id; } tp;
/* reserved for future CAN protocols address information */
} can_addr;
};