/*
 * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
 * All rights reserved.
 *
 * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
 * exclusively with CVA's microcontroller products. This file can be freely
 * distributed within development tools that are supporting such microcontroller
 * products.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */

#ifndef _FLEXCAN_DRV_H_
#define _FLEXCAN_DRV_H_

/*! \brief Contains public interface to various functions related
 *         to the FlexCAN (Flex Controller Area Network) module
 */

/*******************************************************************************
 * the includes
 ******************************************************************************/

#include <stdbool.h>
#include <stdint.h>

/*! \addtogroup flexcan_drv
 *  @{
 */

#ifdef __cplusplus
extern "C" {
#endif

/*******************************************************************************
 * the defines
 ******************************************************************************/
/*! \brief Macro for select message buffer data size for CAN message buffer region
 *
 * The size of each message buffer data will affect the total message buffer number
 */
#define FLEXCANDRV_MB_SIZE_BYTE_8           (0)
#define FLEXCANDRV_MB_SIZE_BYTE_16          (1)
#define FLEXCANDRV_MB_SIZE_BYTE_32          (2)
#define FLEXCANDRV_MB_SIZE_BYTE_64          (3)

/*! \brief Macro for message buffer code
 *
 * The code field was located in message buffer and can be accessed by CPU and by FlexCAN
 * module as part of the message buffer matching and arbitration process.
 */
#define FLEXCANDRV_MSG_BUF_CODE_INACTIVE    (0x0U)
#define FLEXCANDRV_MSG_BUF_CODE_RX_ACTIVE   (0x4U)
#define FLEXCANDRV_MSG_BUF_CODE_TX_REQUEST  (0xCU)
#define FLEXCANDRV_MSG_BUF_CODE_TX_INACTIVE (0x8U)
#define FLEXCANDRV_MSG_BUF_CODE_ABORT       (0x9U)
#define FLEXCANDRV_MSG_BUF_CODE_MASK        (0xFU)
#define FLEXCANDRV_MSG_BUF_CODE_SHIFT       (24U)

/*! \brief Macro for FlexCan access mode
 *
 * The access mode will affect the some of the FlexCan registers access permission
 */
#define FLEXCANDRV_CAN_ACCESS_MODE_USER     (0)
#define FLEXCANDRV_CAN_ACCESS_MODE_SUP      (1)

/*******************************************************************************
 * the typedefs
 ******************************************************************************/
/*! \brief type for data length code (DLC)
 */
typedef enum
{
    DLC_BYTE_0  = 0x00, /*!< 0 byte(s) data length code */
    DLC_BYTE_1  = 0x01, /*!< 1 byte(s) data length code */
    DLC_BYTE_2  = 0x02, /*!< 2 byte(s) data length code */
    DLC_BYTE_3  = 0x03, /*!< 3 byte(s) data length code */
    DLC_BYTE_4  = 0x04, /*!< 4 byte(s) data length code */
    DLC_BYTE_5  = 0x05, /*!< 5 byte(s) data length code */
    DLC_BYTE_6  = 0x06, /*!< 6 byte(s) data length code */
    DLC_BYTE_7  = 0x07, /*!< 7 byte(s) data length code */
    DLC_BYTE_8  = 0x08, /*!< 8 byte(s) data length code */
    DLC_BYTE_12 = 0x09, /*!< 12 byte(s) data length code */
    DLC_BYTE_16 = 0x0A, /*!< 16 byte(s) data length code */
    DLC_BYTE_20 = 0x0B, /*!< 20 byte(s) data length code */
    DLC_BYTE_24 = 0x0C, /*!< 24 byte(s) data length code */
    DLC_BYTE_32 = 0x0D, /*!< 32 byte(s) data length code */
    DLC_BYTE_48 = 0x0E, /*!< 48 byte(s) data length code */
    DLC_BYTE_64 = 0x0F  /*!< 64 byte(s) data length code */
} FlexCanDrv_DLCType;

/*! \brief type for FlexCan clock source
 */
typedef enum
{
    FLEXCANDRV_CLKSRC_OSC    = 0x00, /*!< oscillator clock source */
    FLEXCANDRV_CLKSRC_CHICLK = 0x01  /*!< peripheral clock source */
} FlexCanDrv_ClkSrcType;

/*! \brief type for FlexCan message type
 */
typedef enum
{
    FLEXCANDRV_MSGTYPE_TX, /*!< Tx message type */
    FLEXCANDRV_MSGTYPE_RX  /*!< Rx message type */
} FlexCanDrv_MsgType_t;

/*! \brief type for FlexCan node state type
 */
typedef enum
{
    FLEXCANDRV_NODESTAT_IDLE,         /*!< idle bus state */
    FLEXCANDRV_NODESTAT_RECEIVING,    /*!< receving bus state */
    FLEXCANDRV_NODESTAT_TRANSMITTING, /*!< transmitting bus state*/
} FlexCanDrv_NodeStatType;

/*! \brief type for FlexCan fault confinment state type
 */
typedef enum
{
    FLEXCANDRV_FLTCONFSTS_ERRACTIVE  = 0, /*!< error active state */
    FLEXCANDRV_FLTCONFSTS_ERRPASSIVE = 1, /*!< error passive state */
    FLEXCANDRV_FLTCONFSTS_BUSOFF     = 2, /*!< bus off state */
} FlexCanDrv_FltConfStsType;

/*! \brief type for FlexCan low power mode
 */
typedef enum
{
    FLEXCANDRV_LOWPWRMODE_DOZE, /*!< Doze mode */
    FLEXCANDRV_LOWPWRMODE_STOP, /*!< Stop mode */
} FlexCanDrv_LowPwrModeType;

/*! \brief type for FlexCan Rx FIFO filer format */
typedef enum
{
    FLEXCANDRV_RXFIFO_FILTFORMAT_A, /*!< Format A - One full ID (standard and extended) per ID Filter Table element */
    FLEXCANDRV_RXFIFO_FILTFORMAT_B, /*!< Format B - Two full standard IDs or two partial 14-bit (standard and extended) IDs per ID filter table element */
    FLEXCANDRV_RXFIFO_FILTFORMAT_C, /*!< Format C - Four partial 8-bit standard IDs per ID filter table element */
    FLEXCANDRV_RXFIFO_FILTFORMAT_D, /*!< Format D - All frames rejected */
} FlexCanDrv_RxFifoFiltFormatType;

/*! \brief FlexCan message configuration data structure
 *
 * This structure configures the static attributes for a generic CAN message
 */
typedef struct _FlexCanDrv_MsgCfgType_
{
    uint16_t msgBufId;            /*!< Message buffer index to handle this message object */
    uint16_t msgBufLen;           /*!< Defines number of message buffer to handle this specific
                                       message object configuration, if msgBufLen = 1, then only
                                       single message buffer allocated to this message object,
                                       which is also a common use case, if msgBuf > 1, then multiple
                                       message buffer will allocated to this message object, which
                                       will operating as a software message buffer with depth n */
    uint32_t msgId;               /*!< Message ID can be either 11-bit or 29-bit depends on the
                                       configuration of isExtMsgId */
    bool isExtMsgId;              /*!< Select extended message ID (29-bit) or standard message
                                       ID (11-bit) */
    FlexCanDrv_MsgType_t msgType; /*!< Select message type as Tx message or Rx message */
    FlexCanDrv_DLCType   dlc;     /*!< Message data length code */
    bool                 isFd;    /*!< Select message as classic CAN message or flexible data rate
                                       message */
    bool     intEnable;           /*!< Message Tx / Rx complete interrupt enable */
    uint32_t individualMask;      /*!< Rx indivudual mask for mailbox n */
} FlexCanDrv_MsgCfgType;

/*! \brief FlexCan message object data structure
 *
 * This structure configures the dynamic attributes for a CAN message which can
 * be varied at runtime
 */
typedef struct _FlexCanDrv_MsgObjType_
{
    uint8_t  msgBufId; /*!< Unique ID for message where it located in message buffer */
    uint32_t msgId;    /*!< 11-bit or 29-bit message ID */
    uint8_t  data[64]; /*!< Message data field. Maximum 64 bytes, the valid length was
                            determined by message DLC */
    uint8_t dlc;       /*!< Message DLC get from the latest received message */
} FlexCanDrv_MsgObjType;

/*! \brief FlexCan bit timing configure data structure (CAN / CANFD)
 *
 * This structure configures the CAN / CANFD bit timing parameters
 */
typedef struct _FlexCanDrv_BitTimingType_
{
    uint32_t prescalerDiv;    /*!< Pre-scaler division factor, defines the ratio between CAN module
                                   clock frequency and the serial clock frequency in the data bit
                                   rate portion */
    uint32_t resyncJumpWidth; /*!< Re-sync jump width, the maximum number of time quanta that a bit
                                   time can be changed by one re-synchronization */
    uint32_t propSeg;         /*!< Propagation segment, defines the length of propagation segment in
                                   the bit time  */
    uint32_t phaseSeg1;       /*!< Phase segment 1, defines the length of phase segment 1 in bit time */
    uint32_t phaseSeg2;       /*!< Phase segment 2, defines the length of phase segment 2 in bit time */
} FlexCanDrv_BitTimingType;

typedef struct _FlexCanDrv_InitHwParType_
{
    uint8_t canRamNum; /*!< CAN message buffer RAM number (each RAM block has 512 bytes) */
} FlexCanDrv_InitHwParType;

/*! \brief FlexCan controller (node) configuration data structure
 *
 * This structure configures static attributes for a FlexCAN controller
 */
typedef struct _FlexCanDrv_ControllerCfgType_
{
    FlexCanDrv_ClkSrcType           clkSrc;               /*!< Select the clock source for CAN module */
    bool                            fdEnable;             /*!< Flexible data rate enable */
    bool                            fdISOEnable;          /*!< ISO CAN FD enable */
    bool                            fifoEnable;           /*!< Rx FIFO enable */
    bool                            dmaEnable;            /*!< Rx FIFO DMA enable */
    FlexCanDrv_BitTimingType        bitTiming;            /*!< nominal CAN bit timing struct */
    FlexCanDrv_BitTimingType        fdBitTiming;          /*!< FD CAN bit timing struct */
    uint8_t                         msgBufDataLenSel;     /*!< Message buffer data size selection */
    uint32_t                        rxMBGlobalMask;       /*!< Rx mailbox global mask */
    uint32_t                        rxMB14Mask;           /*!< Rx mailbox 14 mask (only effect in global mask mode) */
    uint32_t                        rxMB15Mask;           /*!< Rx mailbox 15 mask (only effect in global mask mode) */
    uint32_t                        rxFifoGlobalMask;     /*!< Rx fifo global mask */
    FlexCanDrv_RxFifoFiltFormatType rxFifoFiltFormat;     /*!< Rx fifo filter format */
    uint8_t                         rxFifoFilterNum;      /*!< Rx fifo filter number code */
    uint8_t                         rxFifoIndivMskNum;    /*!< Rx fifo individual mask valid number */
    uint32_t                        rxFifoIndivMsk[32];   /*!< Rx fifo individual mask arrary */
    bool                            individualMaskEnable; /*!< Rx individual mask enable */
    bool                            loopbackEnable;       /*!< Loopback mode enable */
    bool                            tdcEnable;            /*!< Transceiver delay compensation enable */
    uint8_t                         tdcOffset;            /*!< Transceiver delay compensation offset */
    uint8_t                         msgNum;               /*!< number of messages */
    const FlexCanDrv_MsgCfgType *   msgCfg;               /*!< message configuration array */
    bool                            edgeWkupEnable;       /*!< CAN edge wakeup enable */
    bool                            txAbortEnable;        /*!< Tx pending message abort mechanism enable */
    bool                            busoffIntEnable;      /*!< Busoff interrupt enable */
    bool                            errorIntEnable;       /*!< Error interrupt enable */
} FlexCanDrv_ControllerCfgType;

/*! \brief FlexCan error states data structure
 *
 * This structure indicating the error states for a FlexCAN controller
 */
typedef struct _FlexCanDrv_ErrStsType_
{
    FlexCanDrv_FltConfStsType fltConfSts;   /*!< fault confinement state */
    uint8_t                   bit1FastErr;  /*!< bit 1 error in FD message data phase */
    uint8_t                   bit0FastErr;  /*!< bit 0 error in FD message data phase */
    uint8_t                   crcFastErr;   /*!< crc error in FD message data phase */
    uint8_t                   formFastErr;  /*!< form error in FD message data phase */
    uint8_t                   stuffFastErr; /*!< stuff error in FD message data phase */
    uint8_t                   bit1Err;      /*!< bit 1 error */
    uint8_t                   bit0Err;      /*!< bit 0 error */
    uint8_t                   ackErr;       /*!< acknowledgement error */
    uint8_t                   crcErr;       /*!< crc error */
    uint8_t                   formErr;      /*!< form error */
    uint8_t                   stuffErr;     /*!< stuff error */
} FlexCanDrv_ErrStsType;

struct _FlexCanRegType_;

typedef struct _FlexCanDrvType_
{
    struct _FlexCanRegType_ *flexCanReg;
    struct _Pcc1RegType_    *pcc1Reg;
    struct _Pcc0RegType_    *pcc0Reg;
    struct _Scg0RegType_    *scg0Reg;
    struct _Scg2RegType_    *scg2Reg;
    struct _SimRegType_     *simReg;
    FlexCanDrv_InitHwParType initHwPar;
} FlexCanDrvType;

/*******************************************************************************
 * the globals
 ******************************************************************************/

/*******************************************************************************
 * the function prototypes
 ******************************************************************************/

/*! \brief Initializes the flexCan driver module
 *
 * This function initializes flexCan driver by setting the register
 * instance to it.
 *
 * \param[in] obj : pointer to FlexCan driver instance
 * \param[in] reg : pointer to FlexCan register instance
 * \param[in] initHwPar: pointer to FlexCan hardware init parameter struct
 */
extern void FlexCanDrv_Init(FlexCanDrvType           *obj,
                            struct _FlexCanRegType_  *flexCanReg,
                            struct _Pcc1RegType_     *pcc1Reg,
                            struct _Pcc0RegType_     *pcc0Reg,
                            struct _Scg0RegType_     *scg0Reg,
                            struct _Scg2RegType_     *scg2Reg,
                            struct _SimRegType_      *simReg,
                            FlexCanDrv_InitHwParType *initHwPar);
/*! \brief Soft reset FlexCAN module
 *
 * This function issues a softreset to FlexCAN module
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 */
extern void FlexCanDrv_SoftReset(FlexCanDrvType *obj);

/*! \brief Start FlexCAN module
 *
 * This function starts the specified FlexCAN device
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 */
extern void FlexCanDrv_Start(FlexCanDrvType *obj);

/*! \brief Configure and initialize FlexCAN controller from user configuration
 *
 * This function configure and initialize the FlexCAN controller from user
 * configuration, it also init FlexCAN RAM area, disable FlexCAN RAM ECC feature
 * and enable the entire FlexCAN module
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] controllerCfg : pointer to FlexCAN controller configuration structure
 */
extern void FlexCanDrv_Configure(FlexCanDrvType *obj, const FlexCanDrv_ControllerCfgType *controllerCfg);

/*! \brief Configure message object and register the specified CAN message buffer
 *
 * This function configure and initialize the CAN message object for its' message ID
 * direction, DLC, FD properties and message buffer interrupt enable. All the above
 * configuration will be stored in the specified message buffer located in CAN RAM
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgCfg : pointer to message object configuration
 * \param[in] msgBufId : message buffer index to store the message object
 */
extern void FlexCanDrv_CfgMsgObj(FlexCanDrvType *obj, const FlexCanDrv_MsgCfgType *msgCfg, uint8_t msgBufId);

/*! \brief Transmit the message unconditionally once
 *
 * This function transmit message unconditionally once by the set the CODE in CS field,
 * this operation shall be performed after message object initialized in message buffer
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj : message buffer object pointer
 */
extern void FlexCanDrv_TransmitMsg(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Set the transmit message object into message buffer
 *
 * This function load the transmit message object into message buffer data field, the data byte order
 * will be re-odered to adapt the message buffer data field format. The data length to load
 * will retrieved from the DLC stored in the specified message buffer
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj : message buffer object pointer
 */
extern void FlexCanDrv_SetTxMsg(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Get the message object from message buffer
 *
 * This function load the message buffer received data and DLC into message object data buffer.
 * The data length to load will retrieved from the DLC stored in the specified message buffer
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj : message buffer object pointer
 */
extern void FlexCanDrv_GetRxMsg(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Get the message object from Rx FIFO
 *
 * This function load the Rx FIFO received data and DLC into message object data buffer.
 * The data length to load will retrieved from the DLC stored in the specified message buffer
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj : message buffer object pointer
 */
extern void FlexCanDrv_GetRxFifoMsg(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Get message object flag, indicating a successful Rx / Tx operation completed
 *
 * This function returns the flag to indicating a successful Rx / Tx operation completed.
 * A clear operation need to be done once the flag is asserted.
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj : message buffer object pointer
 * \return message buffer Tx / Rx operation complete flag
 *             - 0: the corresponding buffer has no occurrence of successfully
 *                  completed transmission or reception
 *             - 1: the corresponding buffer has successfully completed transmission
 *                  or reception
 */
extern uint8_t FlexCanDrv_GetMsgObjFlag(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Get the message object from Rx FIFO
 *
 * This function load the Rx FIFO received data and DLC into message object data buffer.
 * The data length to load will retrieved from the DLC stored in the specified message buffer
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj : message buffer object pointer
 */
extern void FlexCanDrv_GetRxFifoMsg(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Clear message object flag
 *
 * This function clear the correspongding message object flag
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj : message buffer object pointer
 */
extern void FlexCanDrv_ClearMsgObjFlag(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Clear all message object flags
 *
 * This function clear all message object flags
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 */
extern void FlexCanDrv_ClearAllMsgObjFlags(FlexCanDrvType *obj);

/*! \brief Enable interrupt for the corresponding message buffer
 *
 * This function enable interrupt for the corresponding message buffer
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj : message buffer object pointer
 */
extern void FlexCanDrv_EnableMsgObjInterrupt(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Disable interrupt for the corresponding message buffer
 *
 * This function disable interrupt for the corresponding message buffer
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj : message buffer object pointer
 */
extern void FlexCanDrv_DisableMsgObjInterrupt(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Get the default FlexCan controller configuration parameters
 *
 * This function get the default FlexCan controller configuration parameters
 *
 * \param[in] controllerCfg : controller configure pointer
 */
extern void FlexCanDrv_GetDefaultCfg(FlexCanDrv_ControllerCfgType *controllerCfg);

/*! \brief Calculate the CAN bit timing parameters
 *
 * This function calculate the CAN bit timing parameters for both classic and FD CAN
 *
 * \param[out] bitTimingPara : pointer to bit timing parameter group
 * \param[in]  clkFreq       : FlexCan module frequency
 * \param[in]  samplePoint   : Can bit sample point (0 - 10000 -> 0 - 100%)
 * \param[in]  sjw           : Synchronize jump width (0 - 10000 -> 0 - 100%)
 * \param[in]  isFd          : Is the bit timing parameter group for CAN-FD
 */
extern void FlexCanDrv_BitTimingCalc(FlexCanDrv_BitTimingType *bitTimingPara,
                                     uint32_t                  clkFreq,
                                     uint32_t                  baudrate,
                                     uint16_t                  samplePoint,
                                     uint16_t                  sjw,
                                     uint8_t                   isFd);

/*! \brief Get FlexCan error states
 *
 * This function get the FlexCan error states
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \return : node status
 *
 */
FlexCanDrv_NodeStatType FlexCanDrv_GetNodeStatus(FlexCanDrvType *obj);

/*! \brief Get FlexCan error states
 *
 * This function get the FlexCan error states
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[out] errSts: pointer to FlexCan error states
 *
 */
void FlexCanDrv_GetErrorStates(FlexCanDrvType *obj, FlexCanDrv_ErrStsType *errSts);

/*! \brief Abort pending Tx message
 *
 * This function abort the pending Tx message
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] msgObj: message buffer object pointer
 * \return Pending Tx message abort result
 *         - 0: no Tx message transfer pending
 *         - 1: pending Tx message abort success
 *
 */
extern uint8_t FlexCanDrv_AbortPendingTxMsg(FlexCanDrvType *obj, FlexCanDrv_MsgObjType *msgObj);

/*! \brief Set Rx Fifo filter element
 *
 * This function set the fields of the rx fifo flter element according to the filter format configuration
 *
 * \param[in] obj : pointer to FlexCAN driver instance
 * \param[in] filtEleId: rx fifo filter element ID, this ID calcualtion according to the filter format (32, 16, 8 bit)
 * \param[in] isExtId: extended frame indicator
 * \param[in] filtId: filter message ID
 *
 */
extern void FlexCanDrv_SetRxFifoFlitElement(FlexCanDrvType *obj, uint8_t filtEleId, bool isExtId, uint32_t filtId);

#ifdef __cplusplus
}
#endif /* extern "C" */

/*! @}*/

#endif /* #ifndef _FLEXCAN_DRV_H_ */
