/*
 * File      : can.h
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2015, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rt-thread.org/license/LICENSE
 *
 * Change Logs:
 * Date           Author       		Notes
 * 2015-05-14     aubrcool@qq.com 	first version
 */
#ifndef CAN_H_
#define CAN_H_

#ifndef RT_CANMSG_BOX_SZ
#define RT_CANMSG_BOX_SZ 16
#endif
#ifndef RT_CANSND_BOX_NUM
#define RT_CANSND_BOX_NUM 1
#endif

enum CANBAUD
{
        CAN1MBaud=0,    // 1 MBit/sec
        CAN800kBaud,    // 800 kBit/sec
        CAN500kBaud,    // 500 kBit/sec
        CAN250kBaud,    // 250 kBit/sec
        CAN125kBaud,    // 125 kBit/sec
        CAN100kBaud,    // 100 kBit/sec
        CAN50kBaud,     // 50 kBit/sec
        CAN20kBaud,     // 20 kBit/sec
        CAN10kBaud      // 10 kBit/sec
};
#define RT_CAN_MODE_NORMAL 0
#define RT_CAN_MODE_LISEN 1
#define RT_CAN_MODE_LOOPBACK 2
#define RT_CAN_MODE_LOOPBACKANLISEN 3

#define RT_CAN_MODE_PRIV 0x01
#define RT_CAN_MODE_NOPRIV 0x00

#ifdef RT_CAN_USING_LED
struct  rt_can_led
{
        rt_uint32_t pin,mode,init;
        struct rt_timer* timer;
        const char* timer_name;
};
#endif /*RT_CAN_USING_LED*/

struct rt_can_filter_item
{
        rt_uint32_t id  :29;
        rt_uint32_t ide :1;
        rt_uint32_t rtr :1;
        rt_uint32_t mode :1;
        rt_uint32_t mask;
        rt_int32_t hdr;
        rt_err_t  (*ind)(rt_device_t dev, void* args ,rt_int32_t hdr, rt_size_t size);
        void* args;
};
#ifdef RT_CAN_USING_HDR
#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,ind,args) \
     {\
         id,\
         ide,\
         rtr,\
         mode,\
         mask,\
         -1,\
         ind,\
         args,\
     }
#define RT_CAN_FILTER_STD_INIT(id,ind,args) \
     RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,ind,args)
#define RT_CAN_FILTER_EXT_INIT(id,ind,args) \
     RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF,ind,args)
#define RT_CAN_STD_RMT_FILTER_INIT(id,ind,args) \
     RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF,ind,args)
#define RT_CAN_EXT_RMT_FILTER_INIT(id,ind,args) \
     RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF,ind,args)
#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id,ind,args) \
     RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF,ind,args)
#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,ind,args) \
     RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,ind,args)
#else
#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,args) \
     {\
         id,\
         ide,\
         rtr,\
         mode,\
         mask,\
         -1,\
         args,\
     }
#define RT_CAN_FILTER_STD_INIT(id,args) \
     RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,args)
#define RT_CAN_FILTER_EXT_INIT(id,args) \
     RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF,args)
#define RT_CAN_STD_RMT_FILTER_INIT(id,args) \
     RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF,args)
#define RT_CAN_EXT_RMT_FILTER_INIT(id,args) \
     RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF,args)
#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id,args) \
     RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF,args)
#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,args) \
     RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,args)
#endif

struct rt_can_filter_config
{
        rt_uint32_t count;
        rt_uint32_t actived;
        struct rt_can_filter_item* items;
};
struct can_configure
{
        rt_uint32_t baud_rate;
        rt_uint32_t msgboxsz;
        rt_uint32_t sndboxnumber;
        rt_uint32_t mode      :8;
        rt_uint32_t privmode  :8;
        rt_uint32_t reserved  :16;
        #ifdef RT_CAN_USING_LED
        const struct rt_can_led* rcvled;
        const struct rt_can_led* sndled;
        const struct rt_can_led* errled;
        #endif  /*RT_CAN_USING_LED*/
        rt_uint32_t ticks;
#ifdef RT_CAN_USING_HDR
        rt_uint32_t maxhdr;
#endif
};

#define CANDEFAULTCONFIG \
{\
        CAN1MBaud,\
        RT_CANMSG_BOX_SZ,\
        RT_CANSND_BOX_NUM,\
        RT_CAN_MODE_NORMAL,\
};

struct rt_can_ops;
#define RT_CAN_CMD_SET_FILTER      0x13
#define RT_CAN_CMD_SET_BAUD        0x14
#define RT_CAN_CMD_SET_MODE        0x15
#define RT_CAN_CMD_SET_PRIV        0x16
#define RT_CAN_CMD_GET_STATUS      0x17
#define RT_CAN_CMD_SET_STATUS_IND  0x18

#define RT_DEVICE_CAN_INT_ERR  0x1000

enum RT_CAN_STATUS_MODE
{
        NORMAL = 0,
        ERRWARNING = 1,
        ERRPASSIVE = 2,
        BUSOFF = 4,
};
enum RT_CAN_BUS_ERR
{
        RT_CAN_BUS_NO_ERR = 0,
        RT_CAN_BUS_BIT_PAD_ERR = 1,
        RT_CAN_BUS_FORMAT_ERR = 2,
        RT_CAN_BUS_ACK_ERR = 3,
        RT_CAN_BUS_IMPLICIT_BIT_ERR = 4,
        RT_CAN_BUS_EXPLICIT_BIT_ERR = 5,
        RT_CAN_BUS_CRC_ERR = 6,
};
struct rt_can_status
{
        rt_uint32_t rcverrcnt;
        rt_uint32_t snderrcnt;
        rt_uint32_t errcode;
        rt_uint32_t rcvpkg;
        rt_uint32_t dropedrcvpkg;
        rt_uint32_t sndpkg;
        rt_uint32_t dropedsndpkg;
        rt_uint32_t bitpaderrcnt;
        rt_uint32_t formaterrcnt;
        rt_uint32_t ackerrcnt;
        rt_uint32_t biterrcnt;
        rt_uint32_t crcerrcnt;
        rt_uint32_t rcvchange;
        rt_uint32_t sndchange;
        rt_uint32_t lasterrtype;
};
#ifdef RT_CAN_USING_HDR
struct rt_can_hdr {
        rt_uint32_t connected;
        rt_uint32_t msgs;
        struct rt_can_filter_item filter;
        struct rt_list_node list;
};
#endif
struct rt_can_device;
typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device*, void*);
typedef struct rt_can_status_ind_type
{
    rt_canstatus_ind ind;
    void* args;
} *rt_can_status_ind_type_t;
struct rt_can_device
{
        struct rt_device          parent;

        const struct rt_can_ops *ops;
        struct can_configure   config;
        struct rt_can_status   status;
        rt_uint32_t timerinitflag;
        struct rt_timer timer;
        struct rt_can_status_ind_type status_indicate;
#ifdef RT_CAN_USING_HDR
        struct rt_can_hdr* hdr;
#endif
        void *can_rx;
	void *can_tx;
};
typedef struct rt_can_device *rt_can_t;

#define RT_CAN_STDID 0
#define RT_CAN_EXTID 1
#define RT_CAN_DTR   0
#define RT_CAN_RTR   1

typedef struct rt_can_status * rt_can_status_t;
struct rt_can_msg
{
        rt_uint32_t id  :29;
        rt_uint32_t ide :1;
        rt_uint32_t rtr :1;
        rt_uint32_t rsv :1;
        rt_uint32_t len :8;
        rt_uint32_t priv :8;
        rt_uint32_t hdr :8;
        rt_uint32_t reserved :8;
        rt_uint8_t data[8];
};
typedef struct rt_can_msg* rt_can_msg_t;
struct rt_can_msg_list {
        struct rt_list_node list;
#ifdef RT_CAN_USING_HDR
        struct rt_list_node hdrlist;
        struct rt_can_hdr* owner;
#endif
        struct rt_can_msg data;
};
struct rt_can_rx_fifo
{
	/* software fifo */
	struct rt_can_msg_list *buffer;
        rt_uint32_t freenumbers;
        struct rt_list_node freelist;
        struct rt_list_node uselist;
};

#define RT_CAN__SND_RESUTL_OK 0
#define RT_CAN__SND_RESUTL_ERR 1
#define RT_CAN__SND_RESUTL_WAIT 2

#define RT_CAN_EVENT_RX_IND          0x01    /* Rx indication */
#define RT_CAN_EVENT_TX_DONE         0x02    /* Tx complete   */
#define RT_CAN_EVENT_TX_FAIL         0x03    /* Tx complete   */
#define RT_CAN_EVENT_RX_TIMEOUT      0x05    /* Rx timeout    */
#define RT_CAN_EVENT_RXOF_IND        0x06    /* Rx overflow */

struct rt_can_sndbxinx_list {
        struct rt_list_node list;
        struct rt_completion completion;
        rt_uint32_t result;
};
struct rt_can_tx_fifo
{
  	struct rt_can_sndbxinx_list *buffer;
	struct rt_completion completion;
        struct rt_list_node freelist;
};
struct rt_can_ops
{
        rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg);
        rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
        int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno);
        int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno);
};
rt_err_t rt_hw_can_register(struct rt_can_device *can,
                               const char              *name,
                               const struct rt_can_ops *ops,
                               void                    *data);
void rt_hw_can_isr(struct rt_can_device *can, int event);
#endif /*_CAN_H*/
