From d92ffe2966d6ce939da4c9251cd5db173adab2d8 Mon Sep 17 00:00:00 2001
From: xudx <xudx@bluesun.com>
Date: Wed, 13 Nov 2024 15:16:23 +0800
Subject: [PATCH] [ADD] can driver

---
 drv/drv_can.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drv/drv_can.h |  33 ++++++
 2 files changed, 334 insertions(+)

diff --git a/drv/drv_can.c b/drv/drv_can.c
index e69de29..d420a5f 100644
--- a/drv/drv_can.c
+++ b/drv/drv_can.c
@@ -0,0 +1,301 @@
+#include "drv_can.h"
+#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 "drv_can.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[300] = {0}, command[50] = {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, &para.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[i];
+            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[i] = buff[frame_numb * 8 + i]; /*填充发送数据*/
+        }
+        func_send_can_frame(fd, &frame, param);
+        frame_numb++;
+        if (remain_frame_len == 0)
+        {
+            return len;
+        }
+    }
+    return len;
+}
\ No newline at end of file
diff --git a/drv/drv_can.h b/drv/drv_can.h
index e69de29..d507fd9 100644
--- a/drv/drv_can.h
+++ b/drv/drv_can.h
@@ -0,0 +1,33 @@
+#ifndef __DRV_CAN_H_
+#define __DRV_CAN_H_
+
+#include <linux/can.h>
+
+#define CAN_MODE 0
+#define CAN_FD_MODE 1
+#define _DEFAULT_SOURCE
+
+/*CAN口参数结构体 */
+typedef struct
+{
+    unsigned long baudrate;      /*波特率 5k~1000k*/
+    unsigned int id;             /*设备ID*/
+    struct can_filter filter;    /*接收设备过滤ID*/
+    unsigned char extend;        /*扩展ID*/
+    unsigned char loopback_mode; /*回环模式*/
+
+    unsigned char canfd_mode;    /*CANFD模式*/
+    unsigned long data_baudrate; /*CANFD模式下需要单独设置数据波特率*/
+} struct_can_param;
+
+int func_open_can(char *device, struct_can_param para);
+int func_set_can(int fd, struct_can_param para);
+int func_receive_can_buff(int fd, unsigned char *buff, int len);
+int func_send_can_buff(int fd, unsigned char *buff, int len, struct_can_param param);
+
+// int func_open_canfd(char *device, struct_can_param para);
+// int func_set_canfd(int fd, struct_can_param para);
+// int func_receive_canfd_buff(int fd, unsigned char *buff, int len);
+// int func_send_canfd_buff(int fd, unsigned char *buff, int len, struct_can_param param);
+
+#endif
\ No newline at end of file