linux CAN通讯基于Qt代码编写

由于工作需要,将linux中的can通讯编写到Qt上,通过图形界面的方式演示出来。
linux CAN通讯基于Qt代码编写_第1张图片

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;
};

你可能感兴趣的:(linux,qt,运维)