tx2 can通信之epoll接收

2 篇文章 2 订阅

     上一篇《NVIDIA TX2 CAN端口的使用(一)》介绍了如何在TX2平台上添加CAN相关的模块,本篇将介绍如何进行CAN编码。在linux驱动中,can是以网口的形式进行处理,因此完全可以使用linux下的五种编程模型。以socket为例,常用的IO模型是select、poll、epoll,因本人最近刚学习完epoll(epoll是真心强大,并且好用),所以就直接用了epoll来实现can的应用驱动。

epoll主要包含三个接口函数(相比于select和poll确实精简了不少): 

 1. int epoll_create(int size):epoll 描述符创建函数;                                                                                                                   

2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event):epoll时间注册函数;                                                           

3. int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout): epoll时间等待函数;                                     

鉴于篇幅,这里对epoll不做详细介绍,如果需要学习请移步至《linux高效率编程:epoll和多线程  》。

      按照我自己的使用习惯,通常将外设设计成初始化、打开、接收、发送、 关闭五大接口。这里考虑到CAN协议的多适配和可拓展性,将数据接收设计成回调函数的形式,以便适配各自的数据协议。具体接口如下:     

1.  int can_init(can_device_t* device, char *can_name,callback_fn rec_cb);   

2.  void can_open(can_device_t* candevice);

3.   void can_close(can_device_t* candevice);

4.   int can_transimit(can_device_t *candevice, can_obj_t *obj_buff, int obj_count);                                                                   

参数 简单说明:                                                                                                                                                     

 can_device_t:can设备结构体,                                                                                                                                           

 char *can_name: can口名称,在TX2下有两个,can0和can1;                                                                                 

 callback_fn rec_cb: 这个就是接收数据的回调函数,将接口暴露出来,方便拓展;                                                     

 can_obj_t *obj_buff:需要发送的can报文,发送本来想设计成多帧报文发送,实际项目用不上,也就没有再去实现;

         还有一点需要说明,如果使用epoll模型,接收和发送都可以以事件的形式添加到epoll事件集,让epoll实现自动发送;但我这里考虑到发送时机的灵活性,并未将发送事件添加到epoll,也就是说epoll只是实现了can数据的接收(一般情况下也就足够了,目前这种设计模式完全可以应用在其他外设,比如串口、I2C、SPI等);

 

代码大放送时间:                                                                                                                                       


 -----------------------------------------main.c-------------------------------

/**
  ******************************************************************************
  * Copyright(c) 2018-2023Vincent All rights reserved.
  * - Filename
  * - Author  Vincent
  * - Version V1.0.0
  * - Date    2019/1/5
  * - Brief
  * - FunctionList:
  ******************************************************************************
  * History:
  *
  *
  *
  ******************************************************************************
*/

/* Includes ------------------------------------------------------------------*/
#include "can_interface.h"
#include "dbg.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>

/* prama define discrible -----------------------------------------------------*/

/* strcuct  discrible --------------------------------------------------------*/

/* prama  discrible ---------------------------------------------------------*/

/* private fucntion  declaration --------------------------------------------*/
void canrecive(int can_id, uint8_t *buf, int buf_len)
{
    int i;
    printf("ID: 0x%04X,LEN: %02d\t", can_id, buf_len);
    for (i = 0; i < buf_len; i++)
    {
        printf("%02X  ", *(buf + i));
    }
    printf("\r\n");
}
/*--------------------------------------------------------------------------
- @Name:
- @Discrible:
- @Param:
- @Return:
- @Others:
--------------------------------------------------------------------------
- @Recode    date       version         author             modify
-          ------------------------------------------------------------------
-          20190130      V1.0          VINCENT            Create
-
--------------------------------------------------------------------------*/
int main()
{
    int ret ;
    can_device_t vcu_can;
    can_obj_t send_obj;
    uint8_t i = 0;

    ret = can_init(&vcu_can, "can0", canrecive);
    if(ret < 0 )
    {
        printf(">> can device init error!\r\n");
        return 0;
    }
    can_open(&vcu_can);

    while (1)
    {
        sleep(2);
        send_obj.id = i++;
        strcpy(send_obj.data_buf, "HELLO");
        send_obj.data_len = strlen("HELLO");

        printf("send: ID: 0x%04X   len: %02d\r\n", send_obj.id, send_obj.data_len);
        can_transimit(&vcu_can, &send_obj, 1);
    }
    can_close(&vcu_can);
    return 0;
}
/************************ (.c) END OF FILE ************************************/

 -----------------------------------------can_interface.H-------------------------------

/**
  ******************************************************************************
  * Copyright(c) 2018-2023Vincent All rights reserved. 
  * - Filename:    
  * - Author:    Vincent
  * - Version:   V1.0.0
  * - Date:      2019/1/5
  * - Brief:   
  * - FunctionList:
  ******************************************************************************
  * History:
  *   
  *
  * 
  ******************************************************************************
*/
#ifndef __CAN_INTERFACE_H__
#define __CAN_INTERFACE_H__
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdlib.h>

/* prama define discrible -----------------------------------------------------*/
#define CAN_RX_MSG_BUF          ((int)128)
#define CAN_TX_MSG_BUF          ((int)128)
#define CAN_MSG_LEN             ((int)8)   

/* strcuct  discrible --------------------------------------------------------*/
typedef void (*callback_fn)(int,uint8_t*,int);

/* can 消息结构体*/
typedef struct 
{
   uint16_t id;
   uint16_t time_stamp;
   uint8_t  time_flag;
   uint8_t  send_type;
   uint8_t  remote_type;
   uint8_t  extern_flag;
   uint8_t  data_len;
   uint8_t  data_buf[CAN_MSG_LEN];
   uint8_t  reserved[3];   
}can_obj_t;


/* 设备结构体*/
typedef struct 
{
  int sock_fd;
  int epoll_fd;
  callback_fn recive_callback;
}can_device_t;

/* prama  discrible ---------------------------------------------------------*/


/* private fucntion  declaration --------------------------------------------*/


/* private fucntion  discrible -----------------------------------------------*/
int can_init(can_device_t* device, char *can_name,callback_fn rec_cb);
void can_open(can_device_t* candevice);
void can_close(can_device_t* candevice);
int can_transimit(can_device_t *candevice, can_obj_t *obj_buff, int obj_count)
#endif /*__CAN_DRIVER_H__*/
/************************ (.h) END OF FILE ************************************/

-----------------------------------------can_interface.c-------------------------------

/**
  ******************************************************************************
  * Copyright(c) 2018-2023Vincent All rights reserved.
  * - Filename
  * - Author  Vincent
  * - Version V1.0.0
  * - Date    2019/1/5
  * - Brief
  * - FunctionList:
  ******************************************************************************
  * History:
  *
  *
  *
  ******************************************************************************
*/

/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <unistd.h>
#include "dbg.h"
#include "can_interface.h"
/* prama define discrible -----------------------------------------------------*/
#define EPOLL_SIZE 1024
/* strcuct  discrible --------------------------------------------------------*/

/* prama  discrible ---------------------------------------------------------*/
pthread_t can_thread = -1;
static pthread_mutex_t recive_lock;
/* private fucntion  declaration --------------------------------------------*/

/* private fucntion  discrible -----------------------------------------------*/
void *can_recive_thread(void *param);
int can_port_init(char *can_name);
int add_epoll_fd(int sock_fd);
/*--------------------------------------------------------------------------
- @Name:
- @Discrible:
- @Param:
- @Return:
- @Others:
--------------------------------------------------------------------------
- @Recode    date       version         author             modify send_frame
-          ------------------------------------------------------------------
-          20190130      V1.0          VINCENT            Create
-
--------------------------------------------------------------------------*/
int can_init(can_device_t *device, char *can_name, callback_fn rec_cb)
{
    /*bind can 端口*/
    device->sock_fd = can_port_init(can_name);
    if (device->sock_fd < 0)
    {
        printf(">>: can socket create failed!\r\n");
        return -1;
    }

    /*开启epoll事件监听*/
    device ->epoll_fd = add_epoll_fd(device->sock_fd);
    if (device->epoll_fd < 0)
    {
        close(device->sock_fd);
        printf(">>: can socket epoll create failed!\r\n");
        return -1;
    }
    /**注册接收回调函数*/
    if (rec_cb)
    {
        device->recive_callback = rec_cb;
    }

    printf(">>: can init success, sock_fd:  %d,   epoll_fd: %d !\r\n", device->sock_fd, device->epoll_fd);
    return 1;
}

/*--------------------------------------------------------------------------
- @Name:
- @Discrible:
- @Param:
- @Return:
- @Others:
--------------------------------------------------------------------------
- @Recode    date       version         author             modify send_frame
-          ------------------------------------------------------------------
-          20190130      V1.0          VINCENT            Create
-
--------------------------------------------------------------------------*/
void can_open(can_device_t *candevice)
{
    /*创建接收进程*/
    pthread_mutex_init(&recive_lock, NULL);
    pthread_create(&can_thread, NULL, can_recive_thread, candevice);
    printf(">>: epoll thread fd: %d\r\n", (int)can_thread);
}

/*--------------------------------------------------------------------------
- @Name:
- @Discrible:
- @Param:
- @Return:
- @Others:
--------------------------------------------------------------------------
- @Recode    date       version         author             modify send_frame
-          ------------------------------------------------------------------
-          20190130      V1.0          VINCENT            Create
-
--------------------------------------------------------------------------*/
void can_close(can_device_t *candevice)
{
    if (can_thread > 0)
    {
        void *recycle;
        /*回收线程资源  */
        pthread_join(can_thread, &recycle);
        pthread_mutex_destroy(&recive_lock);
        printf(">>: epoll thread destroy!\r\n");
    }
    /*关闭epoll*/
    if (candevice->epoll_fd > 0)
    {
        close(candevice->epoll_fd);
        printf(">>: epoll  close!\r\n");
    }
    /*关闭CAN外设*/
    if (candevice->sock_fd > 0)
    {
        close(candevice->sock_fd);
        printf(">>:  can socket thread destroy!\r\n");
    }
    printf(">>:  can device close!\r\n");
}

/*--------------------------------------------------------------------------
- @Name:
- @Discrible:
- @Param:
- @Return:
- @Others:
--------------------------------------------------------------------------
- @Recode    date       version         author             modify send_frame
-          ------------------------------------------------------------------
-          20190130      V1.0          VINCENT            Create
-
--------------------------------------------------------------------------*/
int can_transimit(can_device_t *candevice, can_obj_t *obj_buff, int obj_count)
{
    int tran_count_ret = 0;
    struct can_frame tx_frame;

    bzero(&tx_frame, sizeof(tx_frame));
    tx_frame.can_id = obj_buff->id;
    tx_frame.can_dlc = obj_buff->data_len;
    memcpy(tx_frame.data, obj_buff->data_buf, obj_buff->data_len);

    tran_count_ret = write(candevice->sock_fd, &tx_frame, sizeof(tx_frame));
    if (tran_count_ret != sizeof(tx_frame))
    {
        printf(">>:  transimit failed!\r\n");
    }
    return tran_count_ret;
}

/*--------------------------------------------------------------------------
- @Name:
- @Discrible:
- @Param:
- @Return:
- @Others:
--------------------------------------------------------------------------
- @Recode    date       version         author             modify send_frame
-          ------------------------------------------------------------------
-          20190130      V1.0          VINCENT            Create
-
--------------------------------------------------------------------------*/
int can_recive(can_device_t *candevice, can_obj_t *obj_buff, int obj_count)
{
    int recive_count_ret = 0;
    pthread_mutex_lock(&recive_lock);

    pthread_mutex_unlock(&recive_lock);
    return recive_count_ret;
}

/*--------------------------------------------------------------------------
- @Name:
- @Discrible:

- @Param:
- @Return:
- @Others:
--------------------------------------------------------------------------
- @Recode    date       version         author             modify send_frame
-          ------------------------------------------------------------------
-          20190130      V1.0          VINCENT            Create
-
--------------------------------------------------------------------------*/
int can_port_init(char *can_name)
{
    int can_fd;
    struct ifreq ifr;
    struct sockaddr_can addr;
    /*创建套接字*/
    can_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (can_fd < 0)
    {
        return -1;
    }
    /*指定 can 设备*/
    strcpy(ifr.ifr_name, can_name);
    ioctl(can_fd, SIOCGIFINDEX, &ifr);
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;

    /*关闭回环模式*/
    int loopback = 0;   /* 0 = disabled, 1 = enabled (default) */
    setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));

    /*关闭自收自发*/
    int recv_own_msgs = 0; /* 0 = disabled (default), 1 = enabled */
    setsockopt(can_fd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &recv_own_msgs, sizeof(recv_own_msgs));

    /*将套接字与 can0 绑定*/
    bind(can_fd, (struct sockaddr *)&addr, sizeof(addr));
    return can_fd;
}

/*--------------------------------------------------------------------------
- @Name:
- @Discrible:

- @Param:
- @Return:
- @Others:
--------------------------------------------------------------------------
- @Recode    date       version         author             modify send_frame
-          ------------------------------------------------------------------
-          20190130      V1.0          VINCENT            Create
-
--------------------------------------------------------------------------*/
int add_epoll_fd(int sock_fd)
{
    int epfd;
    struct epoll_event event;

    /*创建epoll模型*/
    epfd = epoll_create(EPOLL_SIZE);
    if (epfd < 0)
    {
        return -1;
    }

    /*监听sock_fd 的可读事件*/
    event.data.fd = sock_fd;
    event.events = EPOLLIN;
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, sock_fd, &event) < 0)
    {
        return -1;
    }

    return epfd;
}

/******************************************************************************
* @Function:
* @Discrible:
* @Param:
* @Return:
* @Others:
******************************************************************************
* @Recode    date       version         author             modify
*          ------------------------------------------------------------------
*          20190130      V1.0          VINCENT            Create
*
*******************************************************************************/
void *can_recive_thread(void *param)
{
    int i, nfds;
    int timeout = 2;
    uint64_t nbytes;
    struct can_frame rx_frame;
    struct epoll_event events[EPOLL_SIZE];
    can_device_t *can_device_temp = (can_device_t *)param;

    while (1)
    {
        nfds = epoll_wait(can_device_temp->epoll_fd, events, EPOLL_SIZE, timeout);
        if (nfds < 0)
        {
            //   printf(">>:  epoll wait error!\r\n");
        }
        for (int i = 0; i < nfds; i++)
        {
            if (events[i].events & EPOLLIN)
            {
                nbytes = read(events[i].data.fd, &rx_frame, sizeof(rx_frame));
                if (nbytes > 0)
                {
                    if (can_device_temp->recive_callback)
                    {
                        can_device_temp->recive_callback(rx_frame.can_id, rx_frame.data, rx_frame.can_dlc);
                    }
                }
            }
        }
    }
}
/************************ (.c) END OF FILE ************************************/

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值