查看: 367|回复: 0

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

[复制链接]

该用户从未签到

发表于 2024-11-18 09:27:01 | 显示全部楼层 |阅读模式
分享到:
注意:学习资料可在ElfBoard官方网站“资料”专区获取。
本节用到的源码路径:ELF 1开发板资料包\03-例程源码\03-1 命令行例程源码\06_elf1_cmd_can
can.c
  1. #include <errno.h>
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <fcntl.h>
  8. #include <net/if.h>
  9. #include <sys/ioctl.h>
  10. #include <sys/socket.h>
  11. #include <linux/can.h>
  12. #include <linux/can/raw.h>
  13. #include <termios.h> /*PPSIX 终端控制定义*/
  14. #include "mycan.h"

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

  25.     tmpBuf = destpoint;
  26.     va_start(arg_ptr, fmt);
  27.     ulen = vsprintf(tmpBuf, fmt, arg_ptr);

  28.     va_end(arg_ptr);
  29.     return ulen;
  30. }

  31. /*
  32. * @description     : 打开can外设,设置波特率,创建文件描述符
  33. * @param - *device : 设备名称
  34. * @param - para    : can应用参数
  35. * @return                    : 打开设备执成功返回文件描述符,失败返回-1
  36. */
  37. int func_open_can(char *device, struct_can_param para)
  38. {
  39.     FILE *fstream = NULL;
  40.     char buff[300] = {0}, command[50] = {0};
  41.     int fd = -1;
  42.     struct sockaddr_can addr;
  43.     struct ifreq ifr;

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

  49.     if (NULL == (fstream = popen(command, "w")))
  50.     {
  51.         fprintf(stderr, "execute command failed: %s", strerror(errno));
  52.     }
  53.     while (NULL != fgets(buff, sizeof(buff), fstream))
  54.     {
  55.         printf("%s\n", buff);
  56.         if (strstr(buff, "No such device") || strstr(buff, "Cannot find device"))
  57.             return -1;
  58.     }
  59.     pclose(fstream);
  60.     sleep(1);

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

  73.     if (NULL == (fstream = popen(command, "w")))
  74.     {
  75.         fprintf(stderr, "execute command failed: %s", strerror(errno));
  76.     }
  77.     while (NULL != fgets(buff, sizeof(buff), fstream))
  78.     {
  79.         printf("%s\n", buff);
  80.         if (strstr(buff, "No such device") || strstr(buff, "Cannot find device"))
  81.             return -1;
  82.     }
  83.     pclose(fstream);
  84.     sleep(1);

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

  90.     if (NULL == (fstream = popen(command, "w")))
  91.     {
  92.         fprintf(stderr, "execute command failed: %s", strerror(errno));
  93.     }
  94.     while (NULL != fgets(buff, sizeof(buff), fstream))
  95.     {
  96.         printf("%s\n", buff);
  97.         if (strstr(buff, "No such device") || strstr(buff, "Cannot find device"))
  98.             return -1;
  99.     }
  100.     pclose(fstream);
  101.     sleep(3);

  102.     /* 创建 socket */
  103.     fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
  104.     if (fd < 0)
  105.     {
  106.         printf("socket:%s", strerror(errno));
  107.         return -1;
  108.     }
  109.     /* 设置接口设备名称 */
  110.     strcpy(ifr.ifr_name, device);
  111.     /* 确定接口 index */
  112.     if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
  113.     {
  114.         printf("SIOCGIFINDEX:%s\n", strerror(errno));
  115.         return -1;
  116.     }

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

  126.     return fd;
  127. }

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

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

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

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

  162.     rx_count = recv(fd, pframe, sizeof(*pframe), 0);
  163.     if (rx_count <= 0)
  164.     {
  165.         return rx_count;
  166.     }
  167.     else
  168.     {
  169.         if (pframe->can_id & CAN_EFF_FLAG) /*如果是扩展帧,清除扩展帧标识*/
  170.         {
  171.             pframe->can_id &= (~CAN_EFF_FLAG);
  172.         }
  173.         else
  174.         {
  175.             pframe->can_id &= (~CAN_SFF_MASK);
  176.         }
  177.     }

  178.     return pframe->can_dlc;
  179. }

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

  192.     while (1)
  193.     {
  194.         receive_len = func_receive_can_frame(fd, &frame);
  195.         for (i = 0; i < receive_len; i++)
  196.         {
  197.             *(buff + total_receive_len) = frame.data[i];
  198.             total_receive_len++;
  199.         }
  200.         if ((receive_len < 8) || (total_receive_len > (len - 8)))
  201.         {
  202.             return total_receive_len;
  203.         }
  204.     }
  205.     return total_receive_len;
  206. }

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

  217.     if (param.extend == 1) /*扩展帧增加扩展帧标志*/
  218.     {
  219.         pframe->can_id &= CAN_EFF_MASK;
  220.         pframe->can_id |= CAN_EFF_FLAG;
  221.     }
  222.     else
  223.     {
  224.         pframe->can_id &= CAN_SFF_MASK;
  225.     }
  226.     result = send(fd, pframe, sizeof(struct can_frame), 0);
  227.     if (result == -1)
  228.     {
  229.         printf("send:%s\n", strerror(errno));
  230.         return -1;
  231.     }
  232.     return result;
  233. }

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

  247.     remain_frame_len = len;
  248.     while (1)
  249.     {
  250.         if (remain_frame_len >= 8)
  251.         {
  252.             frame.can_dlc = 8;     /*填充发送长度*/
  253.             remain_frame_len -= 8; /*剩余数据长度*/
  254.         }
  255.         else
  256.         {
  257.             frame.can_dlc = remain_frame_len; /*填充发送长度*/
  258.             remain_frame_len = 0;             //
  259.         }

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

  261.         for (i = 0; i < frame.can_dlc; i++)
  262.         {
  263.             frame.data[i] = buff[frame_numb * 8 + i]; /*填充发送数据*/
  264.         }
  265.         func_send_can_frame(fd, &frame, param);
  266.         frame_numb++;
  267.         if (remain_frame_len == 0)
  268.         {
  269.             return len;
  270.         }
  271.     }
  272.     return len;
  273. }
复制代码

main.c
  1. #include <errno.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <termios.h> /*PPSIX 终端控制定义*/
  8. #include <net/if.h>
  9. #include <sys/ioctl.h>
  10. #include <sys/socket.h>
  11. #include <linux/can.h>
  12. #include <linux/can/raw.h>
  13. #include "mycan.h"

  14. char ver[20] = {"ver01.001"};

  15. int sock_fd;
  16. struct_can_param can_param = {250000, 0x103, {
  17.                                                  0x100,
  18.                                                  0x00,
  19.                                              },
  20.                               0,
  21.                               0,
  22.                               0,
  23.                               2000000};

  24. unsigned char send_buff[1024], receive_buff[1024];
  25. unsigned int send_num = 0, receive_num = 0;

  26. //数据收发应用
  27. char active_send_buff[500] = "test can";
  28. int active_send_mode = 0, active_send_num = 8, active_send_time = 1000, active_send_time_count = 0;
  29. int real_send_num = 0;
  30. int loopback_send_mode = 0;

  31. char dev[20];

  32. /*
  33. * @description : 自定义打印函数
  34. * @param - buff:  打印数据缓冲区
  35. * @param - lens:  打印数据长度
  36. * @param - mode:  打印格式
  37. * @return                : 无
  38. */
  39. void func_my_print(unsigned char *buff, unsigned int lens, unsigned char mode)
  40. {
  41.     int i = 0;

  42.     switch (mode)
  43.     {
  44.     case 'H': //按照16进制打印数据
  45.         for (i = 0; i < lens; i++)
  46.         {
  47.             printf("0X%02X  ", buff[i]);
  48.         }
  49.         break;
  50.     case 'h': //按照16进制打印数据
  51.         for (i = 0; i < lens; i++)
  52.         {
  53.             printf("0x%02x  ", buff[i]);
  54.         }
  55.         break;
  56.     case 'd': //按照10进制打印数据
  57.         for (i = 0; i < lens; i++)
  58.         {
  59.             printf("%02d  ", buff[i]);
  60.         }
  61.         break;
  62.     case 'c': //按照字符打印数据
  63.         for (i = 0; i < lens; i++)
  64.         {
  65.             printf("%c", buff[i]);
  66.         }
  67.         break;
  68.     default:
  69.         break;
  70.     }
  71.     printf("\n");
  72. }

  73. /*
  74. * @description  : 打印参数设置格式
  75. * @param - pname: 函数名
  76. * @return                 : 无
  77. */
  78. static void print_usage(const char *pname)
  79. {
  80.     printf("Usage: %s device [-b baudrate] [-id id_numb] [-filt id mask] [-e] [-fd dbaudrate] [-t data time] [-l] [-L] [-v]"
  81.            "\n\t'-b baudrate' for different baudrate, range 5k to 5M,unit is Kbps"
  82.            "\n\t'-id id_numb' for nonzero can send id"
  83.            "\n\t'-filt id mask' for receive can_id and can_mask"
  84.            "\n\t'-e' for extend id frame"
  85.            "\n\t'-fd dbaudrate' for can fd mode , dbaudrate range 250k to 5M,unit is Kbps"
  86.            "\n\t'-t data time'  for interval set time actively sends the data, unit is s"
  87.            "\n\t'-l' for can loopback mode"
  88.            "\n\t'-L' for app loopback receive data"
  89.            "\n\t'-rf path' save the data received by the serial port into the file, path for file to save"
  90.            "\n\t'-v' show version"
  91.            "\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"
  92.            "\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"
  93.            "\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"
  94.            "\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"
  95.            "\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 ",
  96.            pname);
  97. }

  98. /*
  99. * @description : 解析函数带入参数
  100. * @param - numb: 参数个数
  101. * @param - *param: 带入参数数组指针
  102. * @param - *canparam: can应用参数
  103. * @return                : 无
  104. */
  105. void get_param(int numb, char *param[], struct_can_param *canparam)
  106. {
  107.     int i = 0, len = 0;
  108.     unsigned int baudrate = 0, id = 0, mask = 0, active_param = 0;

  109.     if (numb <= 2)
  110.         return;

  111.     for (i = 2; i < numb; i++)
  112.     {
  113.         if (!strcmp(param[i], "-b"))
  114.         {
  115.             i++;
  116.             baudrate = atoi(param[i]);
  117.             switch (baudrate)
  118.             {
  119.             case 5:
  120.             case 10:
  121.             case 20:
  122.             case 40:
  123.             case 50:
  124.             case 80:
  125.             case 100:
  126.             case 125:
  127.             case 200:
  128.             case 250:
  129.             case 400:
  130.             case 500:
  131.             case 666:
  132.             case 800:
  133.             case 1000:
  134.             case 2000:
  135.             case 4000:
  136.             case 5000:
  137.                 canparam->baudrate = baudrate * 1000;
  138.                 break;
  139.             }
  140.             continue;
  141.         }
  142.         if (!strcmp(param[i], "-id"))
  143.         {
  144.             i++;
  145.             id = strtoul(param[i], NULL, 16);
  146.             if (id)
  147.             {
  148.                 canparam->id = (unsigned int)id;
  149.             }
  150.             continue;
  151.         }
  152.         if (!strcmp(param[i], "-filt"))
  153.         {
  154.             i++;
  155.             id = 0;
  156.             id = strtoul(param[i], NULL, 16);
  157.             canparam->filter.can_id = (canid_t)id;
  158.             i++;
  159.             mask = strtoul(param[i], NULL, 16);
  160.             canparam->filter.can_mask = (canid_t)mask;
  161.             continue;
  162.         }
  163.         if (!strcmp(param[i], "-e"))
  164.         {
  165.             canparam->extend = 1;
  166.             continue;
  167.         }
  168.         if (!strcmp(param[i], "-fd"))
  169.         {
  170.             canparam->canfd_mode = CAN_FD_MODE;

  171.             i++;
  172.             baudrate = atoi(param[i]);
  173.             switch (baudrate)
  174.             {
  175.             case 250:
  176.             case 500:
  177.             case 1000:
  178.             case 2000:
  179.             case 4000:
  180.             case 5000:
  181.                 canparam->data_baudrate = baudrate * 1000;
  182.                 break;
  183.             }
  184.             continue;
  185.         }
  186.         if (!strcmp(param[i], "-t"))
  187.         {
  188.             active_send_mode = 1;

  189.             i++;
  190.             len = strlen(param[i]);
  191.             if (len > 0)
  192.             {
  193.                 active_send_num = len;
  194.                 memcpy(active_send_buff, param[i], len); //要发送的字符串

  195.                 i++;
  196.                 len = atoi(param[i]); //发送间隔
  197.                 if (len > 0)
  198.                 {
  199.                     active_send_time = len * 1000; //转换为ms单位
  200.                     active_send_time_count = active_send_time;
  201.                 }
  202.             }
  203.             continue;
  204.         }
  205.         if (!strcmp(param[i], "-l"))
  206.         {
  207.             canparam->loopback_mode = 1;
  208.             continue;
  209.         }
  210.         if (!strcmp(param[i], "-L"))
  211.         {
  212.             loopback_send_mode = 1;
  213.             continue;
  214.         }
  215.         if (!strcmp(param[i], "-v"))
  216.         {
  217.             printf("can_demo ver:  %s\n", ver);
  218.             continue;
  219.         }
  220.     }
  221. }

  222. /*
  223. * @description  : 主函数
  224. * @param - argc : 参数个数
  225. * @param - *argv: 带入参数数组指针
  226. * @return                 : 执行结果
  227. */
  228. int main(int argc, char *argv[])
  229. {
  230.     int i = 0, result = 0;

  231.     //检测是否有参数
  232.     if (argc < 2 || strncmp(argv[1], "can", 3))
  233.     {
  234.         print_usage(argv[0]);
  235.         exit(1);
  236.     }

  237.     //检测是否有--h或--help
  238.     if ((!strcmp(argv[1], "--h")) || (!strcmp(argv[1], "--help")))
  239.     {
  240.         print_usage(argv[0]);
  241.         exit(1);
  242.     }

  243.     strcpy(dev, argv[1]);

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

  246.     //当知道设备名称时可以直接赋值dev,例strcpy(dev, "can0");
  247.     //打开CAN口 创建socket 绑定socket
  248.     sock_fd = func_open_can(dev, can_param);
  249.     if (sock_fd < 0)
  250.     {
  251.         printf("Can't Open deveice %s \n", dev);
  252.         exit(0);
  253.     }
  254.     else
  255.     {
  256.         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",
  257.                can_param.baudrate / 1000, can_param.id, can_param.filter.can_id, can_param.filter.can_mask,
  258.                can_param.extend, can_param.loopback_mode, can_param.canfd_mode, can_param.data_baudrate / 1000);
  259.         //设置CAN口过滤
  260.         result = func_set_can(sock_fd, can_param);
  261.         if (result < 0)
  262.         {
  263.             perror("set_opt error");
  264.             exit(0);
  265.         }
  266.         //设置CAN口为非阻塞方式
  267.         fcntl(sock_fd, F_SETFL, O_NONBLOCK); //非阻塞
  268.     }

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

  278.         //组织发送数据
  279.         if ((1 == loopback_send_mode) && (receive_num > 0)) //数据回环处理
  280.         {
  281.             send_num = receive_num;
  282.             memcpy(send_buff, receive_buff, receive_num);
  283.         }
  284.         else if (1 == active_send_mode)
  285.         {
  286.             if (active_send_time_count >= active_send_time)
  287.             {
  288.                 active_send_time_count = 0;
  289.                 send_num = active_send_num;
  290.                 memcpy(send_buff, active_send_buff, active_send_num);
  291.             }
  292.             else
  293.             {
  294.                 active_send_time_count++;
  295.             }
  296.         }

  297.         //发送数据
  298.         if (send_num > 0)
  299.         {
  300.             real_send_num = func_send_can_buff(sock_fd, send_buff, send_num, can_param);
  301.             if (real_send_num > 0)
  302.             {
  303.                 printf("[%s nwrite=%d] ", dev, real_send_num);
  304.                 func_my_print(send_buff, real_send_num, 'c');
  305.             }
  306.             memset(send_buff, 0, send_num);
  307.             send_num = 0;
  308.         }
  309.         usleep(1000); // 1ms
  310.     }
  311.     close(sock_fd);
  312.     exit(0);
  313. }
复制代码

进程名:elf1_cmd_can
使用方法:./elf1_cmd_can 设备名 [参数选项]… …
31-33.png

回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /4 下一条



手机版|小黑屋|与非网

GMT+8, 2024-12-19 00:08 , Processed in 0.117166 second(s), 17 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.