/**
 ******************************************************************************
 * @file    kpm32xx_ddl_can.h
 * @author  Kiwi Software Team
 * @brief   Header file of CAN DDL module.
 * @note
 *		   V1.0.0, 2022/08/03.
 *
 * Copyright (c) 2024, Kiwi Instruments Co,. Ltd.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *	1. Redistributions of source code must retain the above copyright notice,
 *	   this list of conditions and the following disclaimer.
 *
 *	2. Redistributions in binary form must reproduce the above copyright notice,
 *	   this list of conditions and the following disclaimer in the documentation
 *	   and/or other materials provided with the distribution.
 *
 *	3. Neither the name of the copyright holder nor the names of its contributors
 *	   may be used to endorse or promote products derived from this software without
 *	   specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************
 */


#ifndef __KPM32xx_DDL_CAN_H
#define __KPM32xx_DDL_CAN_H

#ifdef __cplusplus
extern "C" {
#endif


#include "kpm32xx_ddl_def.h"



/* CAN MAX filter number */
#define CAN_MAX_FILTER_NUM        (2U)

/* CAN Maximum baudrate prescaler value */
#define CAN_MAX_BRP               (4095U)

/* CAN Maximum error warning threshold value */
#define CAN_MAX_ERRWARNTHR        (255U)

/* CAN output control mode */
#define CAN_OPMODE_NORMAL         (CAN_OUTCTRL_OCMODE_NORMAL)
#define CAN_OPMODE_CLOCK          (CAN_OUTCTRL_OCMODE_CLOCK)

/* CAN operating mode */
#define CAN_MODE_INIT             (CAN_CFG_WORKMODE_INIT)        /* Init mode */
#define CAN_MODE_NORMAL           (CAN_CFG_WORKMODE_NORMAL)      /* Normal mode   */
#define CAN_MODE_LISTENONLY       (CAN_CFG_WORKMODE_LISTEN)      /* Listening only mode */
#define CAN_MODE_SELFTEST         (CAN_CFG_WORKMODE_SELFTEST)    /* Seft test mode   */

/* CAN identifier type */
#define CAN_IDTYPE_STD                  (0x00000000U)  /* Standard Id */
#define CAN_IDTYPE_EXT                  (0x00000001U)  /* Extended Id */

/* CAN RTR type */
#define CAN_RTRTYPE_NORMAL            (0x00000000U)  /* Normal data frame */
#define CAN_RTRTYPE_REMOTE            (0x00000001U)  /* Remote transmission request */

/* CAN baudrate */
typedef enum
{
	CAN_BAUDRATE_5KBPS       = 5000U,
	CAN_BAUDRATE_10KBPS      = 10000U,
	CAN_BAUDRATE_20KBPS      = 20000U,
	CAN_BAUDRATE_50KBPS      = 50000U,
	CAN_BAUDRATE_100KBPS     = 100000U,
	CAN_BAUDRATE_125KBPS     = 125000U,
	CAN_BAUDRATE_250KBPS     = 250000U,
	CAN_BAUDRATE_500KBPS     = 500000U,
	CAN_BAUDRATE_800KBPS     = 800000U,
	CAN_BAUDRATE_1000KBPS    = 1000000U,
} CAN_Baudrate_T;

/* CAN time segment 1 */
typedef enum
{
	CAN_TIMESEG1_1TQ         = 0x00U,           /* One time quantum for time segment 1 */
	CAN_TIMESEG1_2TQ,
	CAN_TIMESEG1_3TQ,
	CAN_TIMESEG1_4TQ,
	CAN_TIMESEG1_5TQ,
	CAN_TIMESEG1_6TQ,
	CAN_TIMESEG1_7TQ,
	CAN_TIMESEG1_8TQ,
	CAN_TIMESEG1_9TQ,
	CAN_TIMESEG1_10TQ,
	CAN_TIMESEG1_11TQ,
	CAN_TIMESEG1_12TQ,
	CAN_TIMESEG1_13TQ,
	CAN_TIMESEG1_14TQ,
	CAN_TIMESEG1_15TQ,
	CAN_TIMESEG1_16TQ,
} CAN_TimeSeg1_T;

/* CAN time segment 2 */
typedef enum
{
	CAN_TIMESEG2_1TQ         = 0x00U,            /* One time quantum for time segment 2 */
	CAN_TIMESEG2_2TQ,
	CAN_TIMESEG2_3TQ,
	CAN_TIMESEG2_4TQ,
	CAN_TIMESEG2_5TQ,
	CAN_TIMESEG2_6TQ,
	CAN_TIMESEG2_7TQ,
	CAN_TIMESEG2_8TQ,
} CAN_TimeSeg2_T;

/* CAN synchronization jump width */
typedef enum
{
	CAN_SYNCJUMPWIDTH_1TQ         = 0x00U,       /* One time quantum for synchronization */
	CAN_SYNCJUMPWIDTH_2TQ,
	CAN_SYNCJUMPWIDTH_3TQ,
	CAN_SYNCJUMPWIDTH_4TQ,
} CAN_SyncJumpWidth_T;

/* CAN sample time */
typedef enum
{
	CAN_SAMPLE_ONE                = 0x00U,       /* The bus will be sampled once, for high speed. */
	CAN_SAMPLE_THREE              = 0x01U,       /* The bus will be sampled three times, for low/medium speed. */
} CAN_SampleTime_T;

/* CAN filter configuration structure definition */
typedef struct
{
	uint32_t         acceptCode;               /* Specifies the filter accept identification number. */
	uint32_t         maskCode;                 /* Specifies the filter mask identification number. */
} CAN_Filter_T;

/* CAN TX message header structure definition */
typedef struct
{
	uint32_t stdId;               /* Specifies the standard identifier, from 0 to 0x7FF. */
	uint32_t extId;               /* Specifies the extended identifier, from 0 to 0x1FFFFFFF. */
	uint32_t idType;              /* Specifies the type of identifier for the message. */
	uint32_t rtrType  ;           /* Specifies the type of frame for the message. */
	uint32_t dataLenth;           /* Specifies the length of the frame, from 0 to 8. */
} CAN_TXHeader_T;

/* CAN Rx message header structure definition */
typedef struct
{
	uint32_t stdId; 			  /* Specifies the standard identifier, from 0 to 0x7FF. */
	uint32_t extId; 			  /* Specifies the extended identifier, from 0 to 0x1FFFFFFF. */
	uint32_t idType;			  /* Specifies the type of identifier for the message. */
	uint32_t rtrType; 		      /* Specifies the type of frame for the message. */
	uint32_t dataLenth; 		  /* Specifies the length of the frame, from 0 to 8. */
} CAN_RXHeader_T;

/* CAN bus timing structure definition */
typedef struct
{
	CAN_SampleTime_T       sample;                   /* Specifies the sample time. */
	CAN_SyncJumpWidth_T    syncJumpWidth;            /* Specifies synchronization jump width. */
	CAN_TimeSeg1_T         timeSeg1;                 /* Specifies the number of time quanta in time segment 1. */
	CAN_TimeSeg2_T         timeSeg2;                 /* Specifies the number of time quanta in time segment 2. */
} CAN_BusTiming_T;

/* CAN init structure definition */
typedef struct
{
	uint32_t         mode;                         /* Specifies the CAN operating mode. */
	uint32_t         outputMode;                   /* Specifies the output control mode, normal or clock output control mode. */
	CAN_Baudrate_T   baudrate;                     /* Specifies the CAN communication baudrate. */
	uint32_t         errWarnThreshold;             /* Specifies the error number to generate error warning interrupt. */
	CAN_BusTiming_T  busTime;                      /* Specifies the bus timing parameters */
} CAN_Init_T;

/* CAN arbitration lost bit */
typedef enum
{
	CAN_ARBITLOST_ID28            = 0,
	CAN_ARBITLOST_ID27,
	CAN_ARBITLOST_ID26,
	CAN_ARBITLOST_ID25,
	CAN_ARBITLOST_ID24,
	CAN_ARBITLOST_ID23,
	CAN_ARBITLOST_ID22,
	CAN_ARBITLOST_ID21,
	CAN_ARBITLOST_ID20,
	CAN_ARBITLOST_ID19,
	CAN_ARBITLOST_ID18,
	CAN_ARBITLOST_SRTR,
	CAN_ARBITLOST_IDE ,
	CAN_ARBITLOST_ID17,
	CAN_ARBITLOST_ID16,
	CAN_ARBITLOST_ID15,
	CAN_ARBITLOST_ID14,
	CAN_ARBITLOST_ID13,
	CAN_ARBITLOST_ID12,
	CAN_ARBITLOST_ID11,
	CAN_ARBITLOST_ID10,
	CAN_ARBITLOST_ID9,
	CAN_ARBITLOST_ID8,
	CAN_ARBITLOST_ID7,
	CAN_ARBITLOST_ID6,
	CAN_ARBITLOST_ID5,
	CAN_ARBITLOST_ID4,
	CAN_ARBITLOST_ID3,
	CAN_ARBITLOST_ID2,
	CAN_ARBITLOST_ID1,
	CAN_ARBITLOST_ID0,
	CAN_ARBITLOST_RTR,
} CAN_ArbitLostBit_T;

/* CAN error code type */
typedef enum
{
	CAN_ERRCODE_BIT      = 0x00U,
	CAN_ERRCODE_FORM,
	CAN_ERRCODE_STUFF,
	CAN_ERRCODE_OTHER,
} CAN_ErrCode_T;

/* CAN error occured direction */
typedef enum
{
	CAN_ERRDIR_TRANSMIT  = 0x00U,
	CAN_ERRDIR_RECEIVE,
} CAN_ErrorDir_T;

/* CAN error occured segment */
typedef enum
{
	CAN_ERRSEGMENT_SOF         = 0x03,
	CAN_ERRSEGMENT_ID28_21     = 0x02,
	CAN_ERRSEGMENT_ID20_18     = 0x06,
	CAN_ERRSEGMENT_SRTR        = 0x04,
	CAN_ERRSEGMENT_IDE         = 0x05,
	CAN_ERRSEGMENT_ID17_13     = 0x07,
	CAN_ERRSEGMENT_ID12_5      = 0x0F,
	CAN_ERRSEGMENT_ID4_0       = 0x0E,
	CAN_ERRSEGMENT_RTR         = 0x0C,
	CAN_ERRSEGMENT_R1          = 0x0D,
	CAN_ERRSEGMENT_R0          = 0x09,
	CAN_ERRSEGMENT_DLC         = 0x0B,
	CAN_ERRSEGMENT_DF          = 0x0A,
	CAN_ERRSEGMENT_CRCS        = 0x08,
	CAN_ERRSEGMENT_CRCD        = 0x18,
	CAN_ERRSEGMENT_ACK         = 0x19,
	CAN_ERRSEGMENT_ACKD        = 0x1B,
	CAN_ERRSEGMENT_EOF         = 0x1A,
	CAN_ERRSEGMENT_INTER       = 0x12,
	CAN_ERRSEGMENT_ACTIVE      = 0x11,
	CAN_ERRSEGMENT_PASSIVE     = 0x16,
	CAN_ERRSEGMENT_TOLERATE    = 0x13,
	CAN_ERRSEGMENT_ERRDEL      = 0x17,
	CAN_ERRSEGMENT_OVERLOAD    = 0x1C,
} CAN_ErrSegment_T;

/* CAN error info structure */
typedef struct
{
	uint32_t          rxErrCnt;            /* Receive error counter */
	uint32_t          txErrCnt;            /* Transmit error counter */
	CAN_ErrCode_T     errType;             /* Error code type */
	CAN_ErrorDir_T    errDir;              /* Error occured direction: 0 for transmit, 1 for receive */
	CAN_ErrSegment_T  errSegment;          /* Error occured in which segment */
} CAN_ErrorInfo_T;


/* Enable the specified CAN interrupts. */
#define __DDL_CAN_ENABLE_IT(__INSTANCE__, __INTERRUPT__) ((__INSTANCE__)->IE |= (__INTERRUPT__))

/* Disable the specified CAN interrupts. */
#define __DDL_CAN_DISABLE_IT(__INSTANCE__, __INTERRUPT__) ((__INSTANCE__)->IE &= ~(__INTERRUPT__))

/* Clear the specified CAN pending flag. */
#define __DDL_CAN_CLEAR_FLAG(__INSTANCE__, __FLAG__) WRITE_REG((__INSTANCE__)->INTST, __FLAG__)

/* Configure work mode */
#define __DDL_CAN_CONFIGURE_MODE(__INSTANCE__, __MODE__)  SET_BITMASK((__INSTANCE__)->CFG, CAN_CFG_WORKMODE_Mask, __MODE__)

/* Check bus off or not, 1 : bus off */
#define IS_CAN_BUS_OFF(__INSTANCE__)  (((__INSTANCE__)->ST & CAN_ST_BUSOFF_Mask) >> CAN_ST_BUSOFF_Pos)


#define IS_CAN_MODE(MODE) (((MODE) == CAN_MODE_INIT) || \
                           ((MODE) == CAN_MODE_NORMAL)|| \
                           ((MODE) == CAN_MODE_LISTENONLY) || \
                           ((MODE) == CAN_MODE_SELFTEST))

#define IS_CAN_STDID(STDID)   ((STDID) <= 0x7FFU)

#define IS_CAN_EXTID(EXTID)   ((EXTID) <= 0x1FFFFFFFU)

#define IS_CAN_DLC(DLC)       ((DLC) <= 8U)

#define IS_CAN_IDTYPE(IDTYPE)  (((IDTYPE) == CAN_IDTYPE_STD) || ((IDTYPE) == CAN_IDTYPE_EXT))

#define IS_CAN_RTR(RTR) (((RTR) == CAN_RTRTYPE_NORMAL) || ((RTR) == CAN_RTRTYPE_REMOTE))


/**
  * @brief  Configure the filter to receive message.
  * @param  CANx         CAN instance.
  * @param  filter       store the filter's configuration
  * @param  filterIndex  specify the index of filter to use
  * @retval None
  * @note   Only can configure filter in INIT mode.
  */
void DDL_CAN_ConfigFilter(CAN_Type *CANx, CAN_Filter_T *filter, uint8_t filterIndex);

/**
  * @brief  Check which bit lost the arbitration.
  * @param  CANx   CAN instance.
  * @retval RTR or the index of identifier
  */
uint8_t DDL_CAN_GetArbitLostBit(CAN_Type *CANx);

/**
  * @brief  Get the error information.
  * @param  CANx     CAN instance.
  * @param  errInfo  pointer to a CAN_ErrorInfo_T structure that contains
  *                  the error information.
  * @retval None
  */
void DDL_CAN_GetErrInfor(CAN_Type *CANx, CAN_ErrorInfo_T *errInfo);

/**
  * @brief  Make specified CAN active.
  * @param  CANx        CAN instance.
  * @retval None.
  */
void DDL_CAN_Instance_Active(CAN_Type *CANx);

/**
  * @brief  Make specified CAN deactive.
  * @param  CANx        CAN instance.
  * @retval None.
  */
void DDL_CAN_Instance_Deactive(CAN_Type *CANx);

/**
  * @brief  Configure the elements of structure CAN_Init_T to default values.
  * @param  pCANStruct Pointer to a CAN_Init_T structure that contains
  *         the configuration information for the given CAN module.
  * @retval None
  */
void DDL_CAN_StructInit(CAN_Init_T *pCANStruct);

/**
  * @brief  Initializes the CAN peripheral.
  * @param  CANx   CAN instance.
  * @param  pCANStruct Pointer to a CAN_Init_T structure that contains
  *         the configuration information for the given CAN module.
  * @retval DDL status
  */
DDL_Status_T DDL_CAN_Init(CAN_Type *CANx, CAN_Init_T *pCANStruct);

/**
  * @brief  Start the CAN module.
  * @param  CANx      CAN instance.
  * @param  pCANStruct Pointer to a CAN_Init_T structure that contains
  *         the configuration information for the given CAN module.
  * @retval None
  */
void DDL_CAN_Start(CAN_Type *CANx, CAN_Init_T *pCANStruct);

/**
  * @brief  Enable CAN interrupt with specified type.
  * @param  CANx      CAN instance.
  * @param  intrMask  CAN interrupt type.
  * @retval None.
  */
void DDL_CAN_IntEnable(CAN_Type *CANx, uint32_t intrMask);

/**
  * @brief  Disable CAN interrupt with specified type.
  * @param  CANx      CAN instance.
  * @param  intrMask  CAN interrupt type.
  * @retval None.
  */
void DDL_CAN_IntDisable(CAN_Type *CANx, uint32_t intrMask);

/**
  * @brief  Request to enter the sleep mode (low power).
  * @param  CANx   CAN instance.
  * @retval None.
  * @note   Only can enter into sleep mode in normal mode.
  */
void DDL_CAN_RequestSleep(CAN_Type *CANx);

/**
  * @brief  Wake up from sleep mode.
  * @param  CANx   CAN instance.
  * @retval None.
  */
void DDL_CAN_WakeUp(CAN_Type *CANx);

/**
  * @brief  start sending normal message to the bus.
  * @param  CANx     CAN instance.
  * @param  pHeader  pointer to a CAN_TXHeader_T structure.
  * @param  pData    array containing the payload of the TX frame.
  * @retval DDL status
  */
DDL_Status_T DDL_CAN_SendNormalMessage(CAN_Type *CANx, CAN_TXHeader_T *pHeader, uint8_t *pData);

/**
  * @brief  start sending remote reuqest message to the bus.
  * @param  CANx     CAN instance.
  * @param  pHeader  pointer to a CAN_TXHeader_T structure.
  * @retval DDL status
  */
DDL_Status_T DDL_CAN_SendRemoteRequestMessage(CAN_Type *CANx, CAN_TXHeader_T *pHeader);

/**
  * @brief  Abort transmission requests
  * @param  CANx   CAN instance.
  * @retval None
  */
void DDL_CAN_AbortTXRequest(CAN_Type *CANx);

/**
  * @brief  Get an CAN frame from the RX FIFO into the message RAM.
  * @param  CANx   CAN instance.
  * @param  pHeader  pointer to a CAN_RXHeader_T structure where the header
  *                  of the RX frame will be stored.
  * @param  pData    pointer to the buffer where the payload of the RX frame will be stored.
  * @retval DDL status
  */
DDL_Status_T DDL_CAN_ReadMessage(CAN_Type *CANx, CAN_RXHeader_T *pHeader, uint8_t *pData);

/**
  * @brief  Poll for CAN status
  * @param  CANx       CAN instance.
  * @param  stMsk      the CAN status, refer to CAN INTST register.
  * @param  timeout    timeout value in millisecond.
  * @retval DDL status.
  */
DDL_Status_T DDL_CAN_PollForStatus(CAN_Type *CANx, uint32_t stMsk, uint32_t timeout);


#ifdef __cplusplus
}
#endif


#endif /* __KPM32xx_DDL_CAN_H */


