/**
  ******************************************************************************
  * @file    ald_can.h
  * @brief   Header file of CAN Module driver.
  *
  * @version V1.0
  * @date    16 Apr 2017
  * @author  AE Team
  * @note
  *
  * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
  *
  ******************************************************************************
  */

#ifndef __ALD_CAN_H
#define __ALD_CAN_H

#ifdef __cplusplus
extern "C" {
#endif

#include "utils.h"

/** @addtogroup ES32FXXX_ALD
  * @{
  */

/** @addtogroup CAN
  * @{
  */

/** @defgroup CAN_Public_Types CAN Public Types
  * @{
  */
/**
  * @brief  ALD State structures definition
  */
typedef enum {
	CAN_STATE_RESET      = 0x00,	/**< CAN not yet initialized or disabled */
	CAN_STATE_READY      = 0x01,	/**< CAN initialized and ready for use */
	CAN_STATE_BUSY       = 0x02,	/**< CAN process is ongoing */
	CAN_STATE_BUSY_TX    = 0x11,	/**< CAN process is ongoing */
	CAN_STATE_BUSY_RX    = 0x21,	/**< CAN process is ongoing */
	CAN_STATE_BUSY_TX_RX = 0x31,	/**< CAN process is ongoing */
	CAN_STATE_TIMEOUT    = 0x03,	/**< CAN in Timeout state */
	CAN_STATE_ERROR      = 0x04,	/**< CAN error state */
} can_state_t;

/**
  * @brief CAN Error Code
  */
typedef enum {
	CAN_ERROR_NONE = 0x00,		/**< No error */
	CAN_ERROR_EWG  = 0x01,		/**< EWG error */
	CAN_ERROR_EPV  = 0x02,		/**< EPV error */
	CAN_ERROR_BOF  = 0x04,		/**< BOF error */
	CAN_ERROR_STF  = 0x08,		/**< Stuff error */
	CAN_ERROR_FOR  = 0x10,		/**< Form error */
	CAN_ERROR_ACK  = 0x20,		/**< Acknowledgment error */
	CAN_ERROR_BR   = 0x40,		/**< Bit recessive */
	CAN_ERROR_BD   = 0x80,		/**< LEC dominant */
	CAN_ERROR_CRC  = 0x100,		/**< LEC transfer error */
} can_error_t;

/**
  * @brief CAN Operating Mode
  */
 typedef enum {
	CAN_MODE_NORMAL          =  0x00,	/**< Normal mode */
	CAN_MODE_LOOPBACK        =  0x01,	/**< Loopback mode */
	CAN_MODE_SILENT          =  0x02,	/**< Silent mode */
	CAN_MODE_SILENT_LOOPBACK =  0x03,  	/**< Loopback combined with silent mode */
} can_operate_mode_t;

/**
  * @brief CAN Synchronization Jump Width
  */
typedef enum {
	CAN_SJW_1 = 0x0,	/**< 1 time quantum */
	CAN_SJW_2 = 0x1,	/**< 2 time quantum */
	CAN_SJW_3 = 0x2,	/**< 3 time quantum */
	CAN_SJW_4 = 0x3,	/**< 4 time quantum */
} can_sjw_t;

/**
  * @brief CAN Time Quantum in Bit Segment 1
  */
typedef enum {
	CAN_SEG1_1  = 0x0,	/**< 1 time quantum */
	CAN_SEG1_2  = 0x1,	/**< 2 time quantum */
	CAN_SEG1_3  = 0x2,	/**< 3 time quantum */
	CAN_SEG1_4  = 0x3,	/**< 4 time quantum */
	CAN_SEG1_5  = 0x4,	/**< 5 time quantum */
	CAN_SEG1_6  = 0x5,	/**< 6 time quantum */
	CAN_SEG1_7  = 0x6,	/**< 7 time quantum */
	CAN_SEG1_8  = 0x7,	/**< 8 time quantum */
	CAN_SEG1_9  = 0x8,	/**< 9 time quantum */
	CAN_SEG1_10 = 0x9,	/**< 10 time quantum */
	CAN_SEG1_11 = 0xA,	/**< 11 time quantum */
	CAN_SEG1_12 = 0xB,	/**< 12 time quantum */
	CAN_SEG1_13 = 0xC,	/**< 13 time quantum */
	CAN_SEG1_14 = 0xD,	/**< 14 time quantum */
	CAN_SEG1_15 = 0xE,	/**< 15 time quantum */
	CAN_SEG1_16 = 0xF,	/**< 16 time quantum */
} can_seg1_t;

/**
  * @brief CAN Time Quantum in Bit Segment 2
  */
typedef enum {
	CAN_SEG2_1 = 0x0,	/**< 1 time quantum */
	CAN_SEG2_2 = 0x1,     	/**< 2 time quantum */
	CAN_SEG2_3 = 0x2,     	/**< 3 time quantum */
	CAN_SEG2_4 = 0x3,     	/**< 4 time quantum */
	CAN_SEG2_5 = 0x4,     	/**< 5 time quantum */
	CAN_SEG2_6 = 0x5,     	/**< 6 time quantum */
	CAN_SEG2_7 = 0x6,     	/**< 7 time quantum */
	CAN_SEG2_8 = 0x7,     	/**< 8 time quantum */
} can_seg2_t;

/**
  * @brief CAN Filter Mode
  */
typedef enum {
	CAN_FILTER_MODE_MASK = 0x0,	/**< Identifier mask mode */
	CAN_FILTER_MODE_LIST = 0x1,	/**< Identifier list mode */
} can_filter_mode_t;

/**
  * @brief CAN Filter Scale
  */
typedef enum {
	CAN_FILTER_SCALE_16 = 0x0,	/**< Two 16-bit filters */
	CAN_FILTER_SCALE_32 = 0x1,	/**< One 32-bit filter */
} can_filter_scale_t;

/**
  * @brief CAN Filter fifo
  */
typedef enum {
	CAN_FILTER_FIFO0 = 0x0,	/**< FIFO 0 assignment for filter */
	CAN_FILTER_FIFO1 = 0x1,	/**< FIFO 1 assignment for filter */
} can_filter_fifo_t;

/**
  * @brief CAN Identifier Type
  */
typedef enum {
	CAN_ID_STD = 0x0,	/**< Standard Id */
	CAN_ID_EXT = 0x1,	/**< Extended Id */
} can_id_type_t;

/**
  * @brief CAN Remote Transmission Request
  */
typedef enum {
	CAN_RTR_DATA   = 0x0,	/**< Data frame */
	CAN_RTR_REMOTE = 0x1, 	/**< Remote frame */
} can_remote_req_t;

/**
  * @brief CAN Transmit Constants
  */
typedef enum {
	CAN_TX_MAILBOX_0    = 0x0,	/**< TX mailbox index 0 */
	CAN_TX_MAILBOX_1    = 0x1,	/**< TX mailbox index 1 */
	CAN_TX_MAILBOX_2    = 0x2,	/**< TX mailbox index 2 */
	CAN_TX_MAILBOX_NONE = 0x3,	/**< MailBox can't be used */
} can_tx_mailbox_t;

/**
  * @brief  CAN Receive fifo Number
  */
typedef enum {
	CAN_RX_FIFO0 = 0x0,	/**< CAN fifo 0 used to receive */
	CAN_RX_FIFO1 = 0x1,	/**< CAN fifo 1 used to receive */
} can_rx_fifo_t;

/**
  * @brief  CAN Flags
  */
typedef enum {
	CAN_FLAG_SLAK  = (1U << 1),			/**< Sleep acknowledge flag */
	CAN_FLAG_WKU   = (1U << 3),			/**< Wake up flag */
	CAN_FLAG_SLAKI = (1U << 4),			/**< Sleep acknowledge flag */
	CAN_FLAG_RQCP0 = (1U << 20) | (1U << 0),	/**< Request MailBox0 flag */
	CAN_FLAG_TXOK0 = (1U << 20) | (1U << 1),	/**< Transmission OK MailBox0 flag */
	CAN_FLAG_RQCP1 = (1U << 20) | (1U << 8),	/**< Request MailBox1 flag */
	CAN_FLAG_TXOK1 = (1U << 20) | (1U << 9),	/**< Transmission OK MailBox1 flag */
	CAN_FLAG_RQCP2 = (1U << 20) | (1U << 16),	/**< Request MailBox2 flag */
	CAN_FLAG_TXOK2 = (1U << 20) | (1U << 17),	/**< Transmission OK MailBox2 flag */
	CAN_FLAG_TME0  = (1U << 20) | (1U << 26),	/**< Transmit mailbox 0 empty flag */
	CAN_FLAG_TME1  = (1U << 20) | (1U << 27),	/**< Transmit mailbox 1 empty flag */
	CAN_FLAG_TME2  = (1U << 20) | (1U << 28),	/**< Transmit mailbox 2 empty flag */
	CAN_FLAG_FF0   = (2U << 20) | (1U << 3),	/**< FIFO 0 Full flag */
	CAN_FLAG_FOV0  = (2U << 20) | (1U << 4),	/**< FIFO 0 Overrun flag */
	CAN_FLAG_FF1   = (3U << 20) | (1U << 3),	/**< FIFO 1 Full flag */
	CAN_FLAG_FOV1  = (3U << 20) | (1U << 4),	/**< FIFO 1 Overrun flag */
	CAN_FLAG_EWG   = (4U << 20) | (1U << 0),	/**< Error warning flag */
	CAN_FLAG_EPV   = (4U << 20) | (1U << 1),	/**< Error passive flag */
	CAN_FLAG_BOF   = (4U << 20) | (1U << 2),	/**< Bus-Off flag */
} can_flag_t;

/**
  * @brief CAN Interrupts
  */
typedef enum {
	CAN_IT_TME  = (1U << 0),	/**< Transmit mailbox empty interrupt bit */
	CAN_IT_FMP0 = (1U << 1),	/**< FIFO0 message pending interrupt bit */
	CAN_IT_FF0  = (1U << 2),	/**< FIFO0 full interrupt bit */
	CAN_IT_FOV0 = (1U << 3),	/**< FIFO0 overrun interrupt bit */
	CAN_IT_FMP1 = (1U << 4),	/**< FIFO1 message pending interrupt bit */
	CAN_IT_FF1  = (1U << 5),	/**< FIFO1 full interrupt bit */
	CAN_IT_FOV1 = (1U << 6),	/**< FIFO1 overrun interrupt bit */
	CAN_IT_EWG  = (1U << 8),	/**< Error warning interrupt bit */
	CAN_IT_EPV  = (1U << 9),	/**< Error passive interrupt bit */
	CAN_IT_BOF  = (1U << 10),	/**< Bus-off interrupt bit */
	CAN_IT_LEC  = (1U << 11),	/**< Last error code interrupt bit */
	CAN_IT_ERR  = (1U << 15),	/**< Error interrupt bit */
	CAN_IT_WKU  = (1U << 16),	/**< wake-up interrupt bit */
	CAN_IT_SLK  = (1U << 17),	/**< sleep interrupt bit */
} can_it_t;

/**
  * @brief CAN filter configuration structure definition
  */
typedef struct {
	uint32_t id_high;		/**< Specifies the filter identification number */
	uint32_t id_low;		/**< Specifies the filter identification number */
	uint32_t mask_id_high;		/**< Specifies the filter mask number or identification number */
	uint32_t mask_id_low;		/**< Specifies the filter mask number or identification number */
	can_filter_fifo_t fifo;		/**< Specifies the fifo (0 or 1) which will be assigned to the filter. */
	uint32_t number;		/**< Specifies the filter which will be initialized. */
	can_filter_mode_t mode;		/**< Specifies the filter mode to be initialized. */
	can_filter_scale_t scale;	/**< Specifies the filter scale. */
	type_func_t active;		/**< Enable or disable the filter. */
	uint32_t bank_number;		/**< Select the start slave bank filter. */
} can_filter_t;

/**
  * @brief CAN init structure definition
  */
typedef struct {
	uint32_t psc;			/**< Specifies the length of a time quantum. */
	can_operate_mode_t mode;	/**< Specifies the CAN operating mode. */
	can_sjw_t sjw;			/**< Specifies the maximum number of time quanta the CAN hardware is
	                                       allowed to lengthen or shorten a bit to perform resynchronization. */
	can_seg1_t seg1;			/**< Specifies the number of time quanta in Bit Segment 1. */
	can_seg2_t seg2;			/**< Specifies the number of time quanta in Bit Segment 2. */
	type_func_t ttcm;		/**< Enable or disable the time triggered communication mode. */
	type_func_t abom;		/**< Enable or disable the automatic bus-off management. */
	type_func_t awk;		/**< Enable or disable the automatic wake-up mode. */
	type_func_t artx;		/**< Enable or disable the non-automatic retransmission mode. */
	type_func_t rfom;		/**< Enable or disable the Receive fifo Locked mode. */
	type_func_t txmp;		/**< Enable or disable the transmit fifo priority. */
} can_init_t;

/**
  * @brief CAN Tx message structure definition
  */
typedef struct {
	uint32_t std;		/**< Specifies the standard identifier. */
	uint32_t ext;		/**< Specifies the extended identifier. */
	can_id_type_t type;	/**< Specifies the type of identifier for the message that will be transmitted. */
	can_remote_req_t rtr;	/**< Specifies the type of frame for the message that will be transmitted. */
	uint32_t len;		/**< Specifies the length of the frame that will be transmitted. */
	uint8_t data[8];	/**< Contains the data to be transmitted. */
} can_tx_msg_t;

/**
  * @brief CAN Rx message structure definition
  */
typedef struct {
	uint32_t std;		/**< Specifies the standard identifier. */
	uint32_t ext;		/**< Specifies the extended identifier. */
	can_id_type_t type;	/**< Specifies the type of identifier for the message that will be received. */
	can_remote_req_t rtr;	/**< Specifies the type of frame for the received message. */
	uint32_t len;		/**< Specifies the length of the frame that will be received. */
	uint8_t data[8];	/**< Contains the data to be received. */
	uint32_t fmi;		/**< Specifies the index of the filter the message stored in the mailbox passes through. */
	can_rx_fifo_t num;	/**< Specifies the receive fifo number. */
} can_rx_msg_t;

/**
  * @brief CAN handle Structure definition
  */
typedef struct can_handle_s {
	CAN_TypeDef *perh;	/**< Register base address */
	can_init_t init;	/**< CAN required parameters */
	can_rx_msg_t *rx_msg;	/**< Pointer to receive message */
	lock_state_t lock;	/**< CAN locking object */
	can_state_t state;	/**< CAN communication state */
	can_error_t err;	/**< CAN Error code */

	void (*tx_cplt_cbk)(struct can_handle_s *arg);	/**< Tx completed callback */
	void (*rx_cplt_cbk)(struct can_handle_s *arg);	/**< Rx completed callback */
	void (*error_cbk)(struct can_handle_s *arg);	/**< error callback */
} can_handle_t;
/**
  * @}
  */

/** @defgroup CAN_Public_Macro CAN Public Macros
  * @{
  */
#define CAN_RESET_HANDLE_STATE(x)	((x)->state = CAN_STATE_RESET)
#define CAN_RX_MSG_PENDING(x, y)	(((y) == CAN_RX_FIFO0) ? \
	(READ_BIT((x)->perh->RXF0, CAN_RXF0_PEND_MSK)) : (READ_BIT((x)->perh->RXF1, CAN_RXF1_PEND_MSK)))
#define CAN_DBG_FREEZE(x, y)	(MODIFY_REG((x)->perh->CON, CAN_CON_DBGSTP_MSK, (y) << CAN_CON_DBGSTP_POS))
/**
  * @}
  */

/** @defgroup CAN_Private_Macros CAN Private Macros
  * @{
  */
#define IS_CAN_ALL(x)	((x) == CAN0)
#define IS_CAN_FILTER_NUMBER(x) ((x) <= 13)
#define IS_CAN_MODE(x)	(((x) == CAN_MODE_NORMAL)   || \
                         ((x) == CAN_MODE_LOOPBACK) || \
                         ((x) == CAN_MODE_SILENT)   || \
                         ((x) == CAN_MODE_SILENT_LOOPBACK))
#define IS_CAN_SJW(x)	(((x) == CAN_SJW_1) || \
                         ((x) == CAN_SJW_2) || \
                         ((x) == CAN_SJW_3) || \
                         ((x) == CAN_SJW_4))
#define IS_CAN_BS1(x)	((x) <= CAN_SEG1_16)
#define IS_CAN_BS2(x)	((x) <= CAN_SEG2_8)
#define IS_CAN_FILTER_MODE(x)	(((x) == CAN_FILTER_MODE_MASK) || \
                                 ((x) == CAN_FILTER_MODE_LIST))
#define IS_CAN_FILTER_SCALE(x)	(((x) == CAN_FILTER_SCALE_16) || \
                                 ((x) == CAN_FILTER_SCALE_32))
#define IS_CAN_FILTER_FIFO(x)	(((x) == CAN_FILTER_FIFO0) || \
                                 ((x) == CAN_FILTER_FIFO1))
#define IS_CAN_IDTYPE(x)	(((x) == CAN_ID_STD) || \
                                 ((x) == CAN_ID_EXT))
#define IS_CAN_RTR(x)	(((x) == CAN_RTR_DATA) || ((x) == CAN_RTR_REMOTE))
#define IS_CAN_FIFO(x)	(((x) == CAN_RX_FIFO0) || ((x) == CAN_RX_FIFO1))
#define IS_CAN_BANKNUMBER(x)	((x) <= 28)
#define IS_CAN_TX_MAILBOX(x)	((x) <= CAN_TX_MAILBOX_NONE)
#define IS_CAN_STDID(x)		((x) <= ((uint32_t)0x7FF))
#define IS_CAN_EXTID(x)		((x) <= ((uint32_t)0x1FFFFFFF))
#define IS_CAN_DATA_LEN(x)	((x) <= ((uint8_t)0x08))
#define IS_CAN_PRESCALER(x)	(((x) >= 1) && ((x) <= 1024))
#define IS_CAN_GET_FLAG(x)	(((x)  == CAN_FLAG_SLAK)  || \
                                  ((x) == CAN_FLAG_WKU)   || \
                                  ((x) == CAN_FLAG_SLAKI) || \
                                  ((x) == CAN_FLAG_RQCP0) || \
                                  ((x) == CAN_FLAG_TXOK0) || \
                                  ((x) == CAN_FLAG_RQCP1) || \
                                  ((x) == CAN_FLAG_TXOK1) || \
                                  ((x) == CAN_FLAG_RQCP2) || \
                                  ((x) == CAN_FLAG_TXOK2) || \
                                  ((x) == CAN_FLAG_TME0)  || \
                                  ((x) == CAN_FLAG_TME1)  || \
                                  ((x) == CAN_FLAG_TME2)  || \
                                  ((x) == CAN_FLAG_FF0)   || \
                                  ((x) == CAN_FLAG_FOV0)  || \
                                  ((x) == CAN_FLAG_FF1)   || \
                                  ((x) == CAN_FLAG_FOV1)  || \
                                  ((x) == CAN_FLAG_EWG)   || \
                                  ((x) == CAN_FLAG_EPV)   || \
                                  ((x) == CAN_FLAG_BOF))
#define IS_CAN_CLEAR_FLAG(x)	(((x)  == CAN_FLAG_WKU)   || \
                                  ((x) == CAN_FLAG_SLAKI) || \
                                  ((x) == CAN_FLAG_RQCP0) || \
                                  ((x) == CAN_FLAG_RQCP1) || \
                                  ((x) == CAN_FLAG_RQCP2) || \
                                  ((x) == CAN_FLAG_FF0)   || \
                                  ((x) == CAN_FLAG_FOV0)  || \
                                  ((x) == CAN_FLAG_FF1)   || \
                                  ((x) == CAN_FLAG_FOV1))
#define IS_CAN_IT(x)		(((x)  == CAN_IT_TME)   || \
                                  ((x) == CAN_IT_FMP0) || \
                                  ((x) == CAN_IT_FF0) || \
                                  ((x) == CAN_IT_FOV0) || \
                                  ((x) == CAN_IT_FMP1) || \
                                  ((x) == CAN_IT_FF1)   || \
                                  ((x) == CAN_IT_FOV1)  || \
                                  ((x) == CAN_IT_EWG)   || \
				  ((x) == CAN_IT_EPV) || \
                                  ((x) == CAN_IT_BOF) || \
                                  ((x) == CAN_IT_LEC) || \
                                  ((x) == CAN_IT_ERR)   || \
                                  ((x) == CAN_IT_WKU)  || \
                                  ((x) == CAN_IT_SLK))
#define CAN_TIMEOUT_VALUE  	100
#define CAN_STATE_TX_MASK	(1U << 4)
#define CAN_STATE_RX_MASK	(1U << 5)
/**
  * @}
  */

/** @addtogroup CAN_Public_Functions
  * @{
  */

/** @addtogroup CAN_Public_Functions_Group1
  *  @{
  */
/* Initialization functions */
void can_reset(can_handle_t *hperh);
ald_status_t can_init(can_handle_t *hperh);
ald_status_t can_filter_config(can_handle_t *hperh, can_filter_t *config);
/**
  * @}
  */

/** @addtogroup CAN_Public_Functions_Group2
  * @{
  */
/* IO operation functions */
ald_status_t can_send(can_handle_t *hperh, can_tx_msg_t *msg, uint32_t timeout);
ald_status_t can_send_by_it(can_handle_t *hperh, can_tx_msg_t *msg);
ald_status_t can_recv(can_handle_t *hperh, can_rx_fifo_t num, can_rx_msg_t *msg, uint32_t timeout);
ald_status_t can_recv_by_it(can_handle_t *hperh, can_rx_fifo_t num, can_rx_msg_t *msg);
/**
  * @}
  */

/** @addtogroup CAN_Public_Functions_Group3
  * @{
  */
/* Control function */
ald_status_t can_sleep(can_handle_t *hperh);
ald_status_t can_wake_up(can_handle_t *hperh);
void can_cancel_send(can_handle_t *hperh, can_tx_mailbox_t box);
void can_irq_handler(can_handle_t *hperh);
type_bool_t can_get_tx_status(can_handle_t *hperh, can_tx_mailbox_t box);
void can_interrupt_config(can_handle_t *hperh, can_it_t it, type_func_t state);
it_status_t can_get_it_status(can_handle_t *hperh, can_it_t it);
flag_status_t can_get_flag_status(can_handle_t *hperh, can_flag_t flag);
void can_clear_flag_status(can_handle_t *hperh, can_flag_t flag);
/**
  * @}
  */

/** @addtogroup CAN_Public_Functions_Group4
  * @{
  */
/* State and Error functions */
can_state_t can_get_state(can_handle_t *hperh);
can_error_t can_get_error(can_handle_t *hperh);
/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

#ifdef __cplusplus
}
#endif

#endif /* __ALD_CAN_H */
