#ifndef __DY_CAN_H_
#define __DY_CAN_H_
#include <linux/can.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <mqueue.h>
#include <pthread.h>
#include <time.h>
#include <sys/select.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
#include <sys/epoll.h>
#include <syslog.h>
#include <linux/can.h>
#include <linux/can/raw.h>

#include "dy_common.h"

#define MAXEPOLLSIZE 20
#define FRAME_TIMEOUT 2000  //ms
#define PACKET_TIMEOUT 3000 //ms
#define MAX_CAN_PORT 2

typedef struct can_cfg_s can_cfg_t;

/*
 * CAN frame 节点数据
 */
typedef struct _can_frame_node_s
{
    struct list_head list;
    gw_port_e port; //对应的port
    struct can_frame frame;
} can_frame_node_t;

typedef struct
{
    int fd;            //can设备的文件描述符
    gw_port_e port;    //对应的port
    char dev_name[12]; //设备名称
    int bitrate;
    int filter_cnt;
    struct can_filter *filters;
    struct list_head rcv_list; //收到的消息列表
    bool disable;
    can_cfg_t *can_cfg;
} can_dev_t;

typedef struct can_cfg_s
{
    int epollfd;
    struct epoll_event *events;
    pthread_mutex_t recv_lock;
    pthread_cond_t recv_cond;
    bool received;
    int node_cnt;
    int (*handle_recv_msg)(void *obj, can_frame_node_t *node);
    int (*handle_recv_frames)(void *obj, struct list_head *nodes);
    can_dev_t can_dev[MAX_CAN_PORT]; //根据配置文件里的can node数量而定
    void *obj;
} can_cfg_t;

typedef struct
{
    canid_t can_id;
    __u8 can_dlc;
    __u8 data[8];
} __attribute__((packed)) can_frame_packed_t;

static inline int can_port_map(int can_port)
{
    int port = 0;

    switch (can_port)
    {
    case CANBUS_0:
        port = 0;
        break;
    case CANBUS_1:
        port = 1;
        break;
    }

    return port;
}

int load_can_cfg_and_init(can_cfg_t *cfg, char *cfg_file);

int can_open(char *dev);
void can_exit(int socketfd);

int can_send_frame(int socket, struct can_frame *pframe);
int can_send_frames(int socket, struct can_frame *pframe);

int can_rcv(int socket, struct can_frame *pframe);
int can_send(int socket, struct can_frame *pframe);

can_cfg_t *dy_can_cfg_init(void *obj, int (*handle_recv_frames)(void *obj, struct list_head *nodes),
                           int (*handle_recv_msg)(void *obj, can_frame_node_t *node));

#endif //__CAN_FRAME_H_
