eefocus_4023189 发表于 2024-11-18 09:27:01

飞凌嵌入式ElfBoard ELF1板卡-CAN编程示例之socket CAN例程

注意:学习资料可在ElfBoard官方网站“资料”专区获取。
本节用到的源码路径:ELF 1开发板资料包\03-例程源码\03-1 命令行例程源码\06_elf1_cmd_can
can.c
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <termios.h> /*PPSIX 终端控制定义*/
#include "mycan.h"

/*
* @description      : 字符串按格式输出
* @param - *destpoint : 字符串格式缓冲区
* @param - *fmt       : 多个参数
* @return                     : 按格式输出字符串缓冲区首指针
*/
char func_dprintf(char *destpoint, char *fmt, ...)
{
    va_list arg_ptr;
    char ulen, *tmpBuf;

    tmpBuf = destpoint;
    va_start(arg_ptr, fmt);
    ulen = vsprintf(tmpBuf, fmt, arg_ptr);

    va_end(arg_ptr);
    return ulen;
}

/*
* @description   : 打开can外设,设置波特率,创建文件描述符
* @param - *device : 设备名称
* @param - para    : can应用参数
* @return                  : 打开设备执成功返回文件描述符,失败返回-1
*/
int func_open_can(char *device, struct_can_param para)
{
    FILE *fstream = NULL;
    char buff = {0}, command = {0};
    int fd = -1;
    struct sockaddr_can addr;
    struct ifreq ifr;

    /*关闭can设备 ifconfig can0 down*/
    memset(buff, 0, sizeof(buff));
    memset(command, 0, sizeof(command));
    func_dprintf(command, "ifconfig %s down", device);
    printf("%s \n", command);

    if (NULL == (fstream = popen(command, "w")))
    {
      fprintf(stderr, "execute command failed: %s", strerror(errno));
    }
    while (NULL != fgets(buff, sizeof(buff), fstream))
    {
      printf("%s\n", buff);
      if (strstr(buff, "No such device") || strstr(buff, "Cannot find device"))
            return -1;
    }
    pclose(fstream);
    sleep(1);

    /*设置can波特率 ip link set can0 up type can bitrate 250000 triple-sampling on*/
    memset(buff, 0, sizeof(buff));
    memset(command, 0, sizeof(command));
    if (para.loopback_mode == 1)
    {
      func_dprintf(command, "ip link set %s up type can bitrate %d triple-sampling on loopback on", device, para.baudrate);
    }
    else
    {
      func_dprintf(command, "ip link set %s up type can bitrate %d triple-sampling on loopback off", device, para.baudrate);
    }
    printf("%s \n", command);

    if (NULL == (fstream = popen(command, "w")))
    {
      fprintf(stderr, "execute command failed: %s", strerror(errno));
    }
    while (NULL != fgets(buff, sizeof(buff), fstream))
    {
      printf("%s\n", buff);
      if (strstr(buff, "No such device") || strstr(buff, "Cannot find device"))
            return -1;
    }
    pclose(fstream);
    sleep(1);

    /*打开can设备 ifconfig can0 up*/
    memset(buff, 0, sizeof(buff));
    memset(command, 0, sizeof(command));
    func_dprintf(command, "ifconfig %s up", device);
    printf("%s \n", command);

    if (NULL == (fstream = popen(command, "w")))
    {
      fprintf(stderr, "execute command failed: %s", strerror(errno));
    }
    while (NULL != fgets(buff, sizeof(buff), fstream))
    {
      printf("%s\n", buff);
      if (strstr(buff, "No such device") || strstr(buff, "Cannot find device"))
            return -1;
    }
    pclose(fstream);
    sleep(3);

    /* 创建 socket */
    fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (fd < 0)
    {
      printf("socket:%s", strerror(errno));
      return -1;
    }
    /* 设置接口设备名称 */
    strcpy(ifr.ifr_name, device);
    /* 确定接口 index */
    if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
    {
      printf("SIOCGIFINDEX:%s\n", strerror(errno));
      return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    /* 绑定 socket到 CAN 接口 */
    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
      printf("bind:%s\n", strerror(errno));
      return -1;
    }

    return fd;
}

/*
* @description : 设置can回环模式和过滤规则
* @param - fd: 文件描述符
* @param - para: can应用参数
* @return                : 设置成功返回1,失败返回-1
*/
int func_set_can(int fd, struct_can_param para)
{
    int loopback = 1;
    int reciveown = 1;

    if (para.loopback_mode == 1)
    {
      // 回环设置 0 关闭回环1 打开回环
      //setsockopt(fd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
      // 接收自己的帧 0 不接收自己帧 1 接收自己帧
      //setsockopt(fd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &reciveown, sizeof(reciveown));
    }

    /* 设置过滤规则 */
    if (setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, ¶.filter, sizeof(para.filter)) < 0)
    {
      printf("error when set filter\n");
      return -1;
    }
    return 1;
}

/*
* @description    : can接收一个can帧
* @param - fd   : 文件描述符
* @param - *pframe: 一个can帧结构体指针
* @return                   : 接收数据长度
*/
int func_receive_can_frame(int fd, struct can_frame *pframe)
{
    int rx_count = 0;

    rx_count = recv(fd, pframe, sizeof(*pframe), 0);
    if (rx_count <= 0)
    {
      return rx_count;
    }
    else
    {
      if (pframe->can_id & CAN_EFF_FLAG) /*如果是扩展帧,清除扩展帧标识*/
      {
            pframe->can_id &= (~CAN_EFF_FLAG);
      }
      else
      {
            pframe->can_id &= (~CAN_SFF_MASK);
      }
    }

    return pframe->can_dlc;
}

/*
* @description: can接收一组数据包
* @param - fd   : 文件描述符
* @param - *buff: 要接收can一组数据的缓冲区首指针
* @param - len: 接收到一组数据的长度
* @return               : 接收数据长度
*/
int func_receive_can_buff(int fd, unsigned char *buff, int len)
{
    int receive_len = 0, total_receive_len = 0;
    struct can_frame frame;
    int i = 0;

    while (1)
    {
      receive_len = func_receive_can_frame(fd, &frame);
      for (i = 0; i < receive_len; i++)
      {
            *(buff + total_receive_len) = frame.data;
            total_receive_len++;
      }
      if ((receive_len < 8) || (total_receive_len > (len - 8)))
      {
            return total_receive_len;
      }
    }
    return total_receive_len;
}

/*
* @description    : can发送一个can帧
* @param - fd   : 文件描述符
* @param - *pframe: 一个can帧结构体指针
* @param - param: can应用参数
* @return                   : 发送数据长度,发送失败返回-1
*/
int func_send_can_frame(int fd, struct can_frame *pframe, struct_can_param param)
{
    int result = 0;

    if (param.extend == 1) /*扩展帧增加扩展帧标志*/
    {
      pframe->can_id &= CAN_EFF_MASK;
      pframe->can_id |= CAN_EFF_FLAG;
    }
    else
    {
      pframe->can_id &= CAN_SFF_MASK;
    }
    result = send(fd, pframe, sizeof(struct can_frame), 0);
    if (result == -1)
    {
      printf("send:%s\n", strerror(errno));
      return -1;
    }
    return result;
}

/*
* @description: can发送一组数据包
* @param - fd   : 文件描述符
* @param - *buff: 要发送can一组数据的缓冲区首指针
* @param - len: 发送数据的长度
* @param - param: can应用参数
* @return               : 实际发送数据长度
*/
int func_send_can_buff(int fd, unsigned char *buff, int len, struct_can_param param)
{
    int remain_frame_len = 0, frame_numb = 0;
    struct can_frame frame;
    int i = 0;

    remain_frame_len = len;
    while (1)
    {
      if (remain_frame_len >= 8)
      {
            frame.can_dlc = 8;   /*填充发送长度*/
            remain_frame_len -= 8; /*剩余数据长度*/
      }
      else
      {
            frame.can_dlc = remain_frame_len; /*填充发送长度*/
            remain_frame_len = 0;             //
      }

      frame.can_id = param.id; /*填充发送id*/

      for (i = 0; i < frame.can_dlc; i++)
      {
            frame.data = buff; /*填充发送数据*/
      }
      func_send_can_frame(fd, &frame, param);
      frame_numb++;
      if (remain_frame_len == 0)
      {
            return len;
      }
    }
    return len;
}
main.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h> /*PPSIX 终端控制定义*/
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include "mycan.h"

char ver = {"ver01.001"};

int sock_fd;
struct_can_param can_param = {250000, 0x103, {
                                                 0x100,
                                                 0x00,
                                             },
                              0,
                              0,
                              0,
                              2000000};

unsigned char send_buff, receive_buff;
unsigned int send_num = 0, receive_num = 0;

//数据收发应用
char active_send_buff = "test can";
int active_send_mode = 0, active_send_num = 8, active_send_time = 1000, active_send_time_count = 0;
int real_send_num = 0;
int loopback_send_mode = 0;

char dev;

/*
* @description : 自定义打印函数
* @param - buff:打印数据缓冲区
* @param - lens:打印数据长度
* @param - mode:打印格式
* @return                : 无
*/
void func_my_print(unsigned char *buff, unsigned int lens, unsigned char mode)
{
    int i = 0;

    switch (mode)
    {
    case 'H': //按照16进制打印数据
      for (i = 0; i < lens; i++)
      {
            printf("0X%02X", buff);
      }
      break;
    case 'h': //按照16进制打印数据
      for (i = 0; i < lens; i++)
      {
            printf("0x%02x", buff);
      }
      break;
    case 'd': //按照10进制打印数据
      for (i = 0; i < lens; i++)
      {
            printf("%02d", buff);
      }
      break;
    case 'c': //按照字符打印数据
      for (i = 0; i < lens; i++)
      {
            printf("%c", buff);
      }
      break;
    default:
      break;
    }
    printf("\n");
}

/*
* @description: 打印参数设置格式
* @param - pname: 函数名
* @return               : 无
*/
static void print_usage(const char *pname)
{
    printf("Usage: %s device [-b baudrate] [-id id_numb] [-filt id mask] [-e] [-fd dbaudrate] [-t data time] [-l] [-L] [-v]"
         "\n\t'-b baudrate' for different baudrate, range 5k to 5M,unit is Kbps"
         "\n\t'-id id_numb' for nonzero can send id"
         "\n\t'-filt id mask' for receive can_id and can_mask"
         "\n\t'-e' for extend id frame"
         "\n\t'-fd dbaudrate' for can fd mode , dbaudrate range 250k to 5M,unit is Kbps"
         "\n\t'-t data time'for interval set time actively sends the data, unit is s"
         "\n\t'-l' for can loopback mode"
         "\n\t'-L' for app loopback receive data"
         "\n\t'-rf path' save the data received by the serial port into the file, path for file to save"
         "\n\t'-v' show version"
         "\n\texample : can0 baudrate 250k id 123 filt_id 105 filt_mask 1f0 extend id string data was send every 2s--> ./can_demo can0 -b 250 -id 123 -filt 105 1f0 -e -t abcdef 2"
         "\n\texample : can1 baudrate 250k id 105 filt_id 123 filt_mask 120 extend id --> ./can_demo can1 -b 250 -id 105 -filt 123 1f0"
         "\n\texample : can0 canfd mode baudrate 250k id 123 filt_id 105 filt_mask 1f0 extend id string data was send every 2s--> ./can_demo can0 -b 250 -id 123 -filt 105 1f0 -e -t 12345678 2 -fd 4000"
         "\n\texample : can1 canfd mode baudrate 250k id 105 filt_id 123 filt_mask 120 extend id --> ./can_demo can1 -b 250 -id 105 -filt 123 1f0 -e -fd 4000"
         "\n\texample : can0 canfd mode baudrate 500k extend id dbaudrate 4000k loopback mode 19 data was send every 1s --> ./can_demo can0 -b 500 -filt 0 0 -fd 4000 -t abcdefg 1 -e -l\n ",
         pname);
}

/*
* @description : 解析函数带入参数
* @param - numb: 参数个数
* @param - *param: 带入参数数组指针
* @param - *canparam: can应用参数
* @return                : 无
*/
void get_param(int numb, char *param[], struct_can_param *canparam)
{
    int i = 0, len = 0;
    unsigned int baudrate = 0, id = 0, mask = 0, active_param = 0;

    if (numb <= 2)
      return;

    for (i = 2; i < numb; i++)
    {
      if (!strcmp(param, "-b"))
      {
            i++;
            baudrate = atoi(param);
            switch (baudrate)
            {
            case 5:
            case 10:
            case 20:
            case 40:
            case 50:
            case 80:
            case 100:
            case 125:
            case 200:
            case 250:
            case 400:
            case 500:
            case 666:
            case 800:
            case 1000:
            case 2000:
            case 4000:
            case 5000:
                canparam->baudrate = baudrate * 1000;
                break;
            }
            continue;
      }
      if (!strcmp(param, "-id"))
      {
            i++;
            id = strtoul(param, NULL, 16);
            if (id)
            {
                canparam->id = (unsigned int)id;
            }
            continue;
      }
      if (!strcmp(param, "-filt"))
      {
            i++;
            id = 0;
            id = strtoul(param, NULL, 16);
            canparam->filter.can_id = (canid_t)id;
            i++;
            mask = strtoul(param, NULL, 16);
            canparam->filter.can_mask = (canid_t)mask;
            continue;
      }
      if (!strcmp(param, "-e"))
      {
            canparam->extend = 1;
            continue;
      }
      if (!strcmp(param, "-fd"))
      {
            canparam->canfd_mode = CAN_FD_MODE;

            i++;
            baudrate = atoi(param);
            switch (baudrate)
            {
            case 250:
            case 500:
            case 1000:
            case 2000:
            case 4000:
            case 5000:
                canparam->data_baudrate = baudrate * 1000;
                break;
            }
            continue;
      }
      if (!strcmp(param, "-t"))
      {
            active_send_mode = 1;

            i++;
            len = strlen(param);
            if (len > 0)
            {
                active_send_num = len;
                memcpy(active_send_buff, param, len); //要发送的字符串

                i++;
                len = atoi(param); //发送间隔
                if (len > 0)
                {
                  active_send_time = len * 1000; //转换为ms单位
                  active_send_time_count = active_send_time;
                }
            }
            continue;
      }
      if (!strcmp(param, "-l"))
      {
            canparam->loopback_mode = 1;
            continue;
      }
      if (!strcmp(param, "-L"))
      {
            loopback_send_mode = 1;
            continue;
      }
      if (!strcmp(param, "-v"))
      {
            printf("can_demo ver:%s\n", ver);
            continue;
      }
    }
}

/*
* @description: 主函数
* @param - argc : 参数个数
* @param - *argv: 带入参数数组指针
* @return               : 执行结果
*/
int main(int argc, char *argv[])
{
    int i = 0, result = 0;

    //检测是否有参数
    if (argc < 2 || strncmp(argv, "can", 3))
    {
      print_usage(argv);
      exit(1);
    }

    //检测是否有--h或--help
    if ((!strcmp(argv, "--h")) || (!strcmp(argv, "--help")))
    {
      print_usage(argv);
      exit(1);
    }

    strcpy(dev, argv);

    //从main函数带来的参数解析为CAN口参数
    get_param(argc, argv, &can_param);

    //当知道设备名称时可以直接赋值dev,例strcpy(dev, "can0");
    //打开CAN口 创建socket 绑定socket
    sock_fd = func_open_can(dev, can_param);
    if (sock_fd < 0)
    {
      printf("Can't Open deveice %s \n", dev);
      exit(0);
    }
    else
    {
      printf("baudrate = %ldK,can_id = 0x%x,can_filter_id = 0x%x,can_filter_mask = 0x%x,extend id = %d,loopback mode = %d,canfd mode = %d,dbaudrate = %ldK\n",
               can_param.baudrate / 1000, can_param.id, can_param.filter.can_id, can_param.filter.can_mask,
               can_param.extend, can_param.loopback_mode, can_param.canfd_mode, can_param.data_baudrate / 1000);
      //设置CAN口过滤
      result = func_set_can(sock_fd, can_param);
      if (result < 0)
      {
            perror("set_opt error");
            exit(0);
      }
      //设置CAN口为非阻塞方式
      fcntl(sock_fd, F_SETFL, O_NONBLOCK); //非阻塞
    }

    while (1)
    {
      //接收数据
      receive_num = func_receive_can_buff(sock_fd, receive_buff, sizeof(receive_buff));
      if (receive_num > 0)
      {
            printf("[%s nread=%d]", dev, receive_num);
            func_my_print(receive_buff, receive_num, 'c'); //将收到的数据打印出来
      }

      //组织发送数据
      if ((1 == loopback_send_mode) && (receive_num > 0)) //数据回环处理
      {
            send_num = receive_num;
            memcpy(send_buff, receive_buff, receive_num);
      }
      else if (1 == active_send_mode)
      {
            if (active_send_time_count >= active_send_time)
            {
                active_send_time_count = 0;
                send_num = active_send_num;
                memcpy(send_buff, active_send_buff, active_send_num);
            }
            else
            {
                active_send_time_count++;
            }
      }

      //发送数据
      if (send_num > 0)
      {
            real_send_num = func_send_can_buff(sock_fd, send_buff, send_num, can_param);
            if (real_send_num > 0)
            {
                printf("[%s nwrite=%d] ", dev, real_send_num);
                func_my_print(send_buff, real_send_num, 'c');
            }
            memset(send_buff, 0, send_num);
            send_num = 0;
      }
      usleep(1000); // 1ms
    }
    close(sock_fd);
    exit(0);
}
进程名:elf1_cmd_can使用方法:./elf1_cmd_can 设备名 [参数选项]… …
页: [1]
查看完整版本: 飞凌嵌入式ElfBoard ELF1板卡-CAN编程示例之socket CAN例程

Baidu
map