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