/*
 * Copyright (c) 2023-2024 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */
#ifndef HPM_MCAN_DRV_H
#define HPM_MCAN_DRV_H

#include "hpm_common.h"
#include "hpm_mcan_regs.h"
#include "hpm_mcan_soc.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief MCAN driver APIs
* @defgroup mcan_interface MCAN driver APIs
* @ingroup mcan_interfaces
* @{
*
*/


enum {
    status_mcan_filter_index_out_of_range = MAKE_STATUS(status_group_mcan, 0),
    status_mcan_rxfifo_empty = MAKE_STATUS(status_group_mcan, 1),
    status_mcan_rxfifo_full = MAKE_STATUS(status_group_mcan, 2),
    status_mcan_txbuf_full = MAKE_STATUS(status_group_mcan, 3),
    status_mcan_txfifo_full = MAKE_STATUS(status_group_mcan, 4),
    status_mcan_rxfifo0_busy = MAKE_STATUS(status_group_mcan, 5),
    status_mcan_rxfifo1_busy = MAKE_STATUS(status_group_mcan, 6),
    status_mcan_txbuf_index_out_of_range = MAKE_STATUS(status_group_mcan, 7),
    status_mcan_rxbuf_index_out_of_range = MAKE_STATUS(status_group_mcan, 8),
    status_mcan_rxbuf_empty = MAKE_STATUS(status_group_mcan, 9),
    status_mcan_tx_evt_fifo_empty = MAKE_STATUS(status_group_mcan, 10),
    status_mcan_timestamp_not_exist = MAKE_STATUS(status_group_mcan, 11),
    status_mcan_ram_out_of_range = MAKE_STATUS(status_group_mcan, 12),
    status_mcan_timeout = MAKE_STATUS(status_group_mcan, 13),
    status_mcan_invalid_bit_timing = MAKE_STATUS(status_group_mcan, 14),
};

/**
 * @brief CAN Interrupt Mask
 */
#define MCAN_INT_ACCESS_TO_RESERVED_ADDR    MCAN_IR_ARA_MASK     /*!< Access to Reserved Address */
#define MCAN_INT_PROTOCOL_ERR_IN_DATA_PHASE MCAN_IR_PED_MASK     /*!< Protocol Error Happened at Data Phase */
#define MCAN_INT_PROTOCOL_ERR_IN_ARB_PHASE  MCAN_IR_PEA_MASK     /*!< Protocol Error Happened at Arbitration Phase */
#define MCAN_INT_WATCHDOG_INT               MCAN_IR_WDI_MASK     /*!< Watchdog interrupt */

#define MCAN_INT_BUS_OFF_STATUS             MCAN_IR_BO_MASK      /*!< Bus-off State Change */
#define MCAN_INT_WARNING_STATUS             MCAN_IR_EW_MASK      /*!< Error Warning State Change */
#define MCAN_INT_ERROR_PASSIVE              MCAN_IR_EP_MASK      /*!< Error Passive State Change */
#define MCAN_INT_ERROR_LOGGING_OVERFLOW     MCAN_IR_ELO_MASK     /*!< Error Logging Overflow */
#define MCAN_INT_BIT_ERROR_UNCORRECTED      MCAN_IR_BEU_MASK     /*!< Bit Error was not corrected */
#define MCAN_INT_BIT_ERROR_CORRECTED        MCAN_IR_BEC_MASK     /*!< Bit Error was corrected */

#define MCAN_INT_MSG_STORE_TO_RXBUF         MCAN_IR_DRX_MASK    /*!< Message was stored to RX Buffer */
#define MCAN_INT_TIMEOUT_OCCURRED           MCAN_IR_TOO_MASK    /*!< Timeout Interrupt */
#define MCAN_INT_MSG_RAM_ACCESS_FAILURE     MCAN_IR_MRAF_MASK   /*!< Message RAM Access Failure */
#define MCAN_INT_TIMESTAMP_WRAPAROUND       MCAN_IR_TSW_MASK    /*!< Timestamp Counter Wrap Around */

#define MCAN_INT_TX_EVT_FIFO_EVT_LOST       MCAN_IR_TEFL_MASK   /*!< TX Event FIFO Element Lost */
#define MCAN_INT_TX_EVT_FIFO_FULL           MCAN_IR_TEFF_MASK   /*!< TX Event FIFO Full */
#define MCAN_INT_TX_EVT_FIFO_WMK_REACHED    MCAN_IR_TEFW_MASK   /*!< TX Event FIFO Watermark Reached */
#define MCAN_INT_TX_EVT_FIFO_NEW_ENTRY      MCAN_IR_TEFN_MASK   /*!< TX Event FIFO New Entry */

#define MCAN_INT_TXFIFO_EMPTY               MCAN_IR_TFE_MASK    /*!< TX FIFO Empty */
#define MCAN_INT_TX_CANCEL_FINISHED         MCAN_IR_TCF_MASK    /*!< Transmission Cancellation Finished */
#define MCAN_INT_TX_COMPLETED               MCAN_IR_TC_MASK     /*!< Transmission Completed */
#define MCAN_INT_HIGH_PRIORITY_MSG          MCAN_IR_HPM_MASK    /*!< High Priority Message */

#define MCAN_INT_RXFIFO1_MSG_LOST           MCAN_IR_RF1L_MASK   /*!< RX FIFO1 Message Lost */
#define MCAN_INT_RXFIFO1_FULL               MCAN_IR_RF1F_MASK   /*!< RX FIFO1 Full */
#define MCAN_INT_RXFIFO1_WMK_REACHED        MCAN_IR_RF1W_MASK   /*!< RX FIFO1 Watermark Reached */
#define MCAN_INT_RXFIFO1_NEW_MSG            MCAN_IR_RF1N_MASK   /*!< RX FIFO1 New Message */

#define MCAN_INT_RXFIFO0_MSG_LOST           MCAN_IR_RF0L_MASK   /*!< RX FIFO0 Message Lost */
#define MCAN_INT_RXFIFO0_FULL               MCAN_IR_RF0F_MASK   /*!< RX FIFO0 Full */
#define MCAN_INT_RXFIFO0_WMK_REACHED        MCAN_IR_RF0W_MASK   /*!< RX FIFO0 Watermark Reached */
#define MCAN_INT_RXFIFO0_NEW_MSG            MCAN_IR_RF0N_MASK   /*!< RX FIFO0 New Message */

/**
 * @brief MCAN Receive Event Flags
 */
#define MCAN_EVENT_RECEIVE (MCAN_INT_RXFIFO0_NEW_MSG | MCAN_INT_RXFIFO1_NEW_MSG | MCAN_INT_MSG_STORE_TO_RXBUF)

/**
 * @brief MCAN Transmit Event Flags
 */
#define MCAN_EVENT_TRANSMIT (MCAN_INT_TX_COMPLETED)
/**
 * @brief MCAN Error Event Flags
 */
#define MCAN_EVENT_ERROR (MCAN_INT_BUS_OFF_STATUS | MCAN_INT_WARNING_STATUS \
                        | MCAN_INT_ERROR_PASSIVE | MCAN_INT_BIT_ERROR_UNCORRECTED \
                        | MCAN_INT_PROTOCOL_ERR_IN_DATA_PHASE | MCAN_INT_PROTOCOL_ERR_IN_ARB_PHASE)

/**
 * @brief Maximum Transmission Retry Count
 */
#define MCAN_TX_RETRY_COUNT_MAX (10000000UL)
/**
 * @brief Maximum Receive Wait Retry Count
 */
#define MCAN_RX_RETRY_COUNT_MAX (80000000UL)

/**
 * @brief MCAN Last Error Code
 */
typedef enum mcan_last_error_code {
    mcan_last_error_code_no_error = 0,      /*!< No error happened */
    mcan_last_error_code_stuff_error,       /*!< Stuff Error */
    mcan_last_error_code_format_error,      /*!< Format Error */
    mcan_last_error_code_ack_error,         /*!< Acknowledge Error */
    mcan_last_error_code_bit1_error,        /*!< Sent logic 1 but monitored value is logic 0 */
    mcan_last_error_code_bit0_error,        /*!< Sent logic 0 but monitored value is logic 1 */
    mcan_last_error_code_crc_error,         /*!< CRC checksum for received message is wrong */
    mcan_last_error_code_no_change,         /*!< Error code was not changed */
} mcan_last_err_code_t;

/**
 * @brief MCAN Communication State
 */
typedef enum mcan_activity_enum {
    mcan_activity_sync = 0,                 /*!< Node is synchronizing on CAN communication */
    mcan_activity_idle,                     /*!< Node is neither receiver nor transmitter */
    mcan_activity_receiver,                 /*!< Node is operating as receiver */
    mcan_activity_transmitter,              /*!< Node is operating as transmitter */
} mcan_activity_state_t;

/***********************************************************************************************************************
 * @brief Default CAN RAM definitions
 **********************************************************************************************************************/
#define MCAN_RAM_WORD_SIZE  (640U)                                  /*!< RAM WORD Size */
/* CAN Filter Element Size Definitions */
#define MCAN_FILTER_ELEM_STD_ID_SIZE (4U)                           /*!< Standard Filter Element Size in Bytes */
#define MCAN_FILTER_ELEM_EXT_ID_SIZE (8U)                           /*!< Extended Filter Element SIze in Bytes */
#define MCAN_STD_FILTER_ELEM_SIZE_MAX (128U)                        /*!< Maximum Standard Filter Element Count */
#define MCAN_EXT_FILTER_ELEM_SIZE_MAX  (64U)                        /*!< Maximum Extended Filter Element Count */
/* MCAN Default Field Size Definitions for CAN2.0 */
#define MCAN_TXRX_ELEM_SIZE_CAN_MAX (4U * sizeof(uint32_t))
#define MCAN_FILTER_SIZE_CAN_DEFAULT (32U)
#define MCAN_TXBUF_SIZE_CAN_DEFAULT (32U)
#define MCAN_RXFIFO_SIZE_CAN_DEFAULT (32U)
#define MCAN_RXBUF_SIZE_CAN_DEFAULT (16U)
/* MCAN Default Field Size Definitions for CANFD */
#define MCAN_TXRX_ELEM_SIZE_CANFD_MAX (18U * sizeof(uint32_t))
#define MCAN_FILTER_SIZE_CANFD_DEFAULT (16U)
#define MCAN_TXBUF_SIZE_CANFD_DEFAULT (8U)
#define MCAN_RXFIFO_SIZE_CANFD_DEFAULT (8U)
#define MCAN_RXBUF_SIZE_CANFD_DEFAULT (4U)

#define MCAN_TXEVT_ELEM_SIZE (8U)

/**
 * @brief CAN Bit Timing Parameters
 */
typedef struct mcan_bit_timing_param_struct {
    uint16_t prescaler; /*!< Data Bit Rate Prescaler */
    uint16_t num_seg1;  /*!< Time segment before sample point (including prop_seg and phase_sge1 */
    uint16_t num_seg2;  /*!< Time segment after sample point */
    uint8_t num_sjw;    /*!< Data (Re)Synchronization Jump Width */
    bool enable_tdc;    /*!< Enable TDC flag, for CANFD data bit timing only */
} mcan_bit_timing_param_t;

/**
 * @brief CAN Bit Timing Options
 */
typedef enum mcan_bit_timing_option {
    mcan_bit_timing_can2_0,          /**< CAN 2.0 bit timing option */
    mcan_bit_timing_canfd_nominal,   /**< CANFD nominal timing option */
    mcan_bit_timing_canfd_data,      /**< CANFD data timing option */
} mcan_bit_timing_option_t;

/**
 * @brief CAN Message Header Size
 */
#define MCAN_MESSAGE_HEADER_SIZE_IN_BYTES (8U)
#define MCAN_MESSAGE_HEADER_SIZE_IN_WORDS (2U)

/**
 * @brief CAN Transmit Message Frame
 *
 * @note Users need to pay attention to the CAN Identifier settings
 *       For standard identifier, the use_ext_id should be set to 0 and the std_id should be used
 *       For extended identifier, the use_ext_id should be set to 1 and the ext_id should be used
 */
typedef struct mcan_tx_message_struct {
    union {
        struct {
            uint32_t ext_id: 29;                        /*!< Extended CAN Identifier */
            uint32_t rtr: 1;                            /*!< Remote Transmission Request */
            uint32_t use_ext_id: 1;                     /*!< Extended Identifier */
            uint32_t error_state_indicator: 1;          /*!< Error State Indicator */
        };
        struct {
            uint32_t : 18;
            uint32_t std_id: 11;                        /*!< Standard CAN Identifier */
            uint32_t : 3;
        };
    };
    struct {
        uint32_t : 8;
        uint32_t message_marker_h: 8;                   /*!< Message Marker[15:8] */
        uint32_t dlc: 4;                                /*!< Data Length Code */
        uint32_t bitrate_switch: 1;                     /*!< Bit Rate Switch */
        uint32_t canfd_frame: 1;                        /*!< CANFD frame */
        uint32_t timestamp_capture_enable: 1;           /*!< Timestamp Capture Enable for TSU */
        uint32_t event_fifo_control: 1;                 /*!< Event FIFO control */
        uint32_t message_marker_l: 8;                   /*!< Message Marker[7:0] */
    };
    union {
        uint8_t data_8[64];                             /*!< Data buffer as byte array */
        uint32_t data_32[16];                           /*!< Data buffer as word array */
    };
} mcan_tx_frame_t;

/**
 * @brief CAN Receive Message Frame
 *
 * @note Users need to pay attention to the CAN Identifier settings
 *       For standard identifier, the use_ext_id should be set to 0 and the std_id should be used
 *       For extended identifier, the use_ext_id should be set to 1 and the ext_id should be used
 */
typedef struct mcan_rx_message_struct {
    union {
        struct {
            uint32_t ext_id: 29;                   /*!< Extended CAN Identifier */
            uint32_t rtr: 1;                       /*!< Remote Frame Flag */
            uint32_t use_ext_id: 1;                /*!< Extended Identifier */
            uint32_t error_state_indicator: 1;     /*!< Error State Indicator */
        };
        struct {
            uint32_t : 18;
            uint32_t std_id: 11;                   /*!< Standard CAN Identifier */
            uint32_t : 3;
        };
    };
    struct {
        union {
            uint16_t rx_timestamp;                  /*!< Received timestamp */
            struct {
                uint16_t rx_timestamp_pointer: 4;   /*!< Timestamp Pointer */
                uint16_t rx_timestamp_captured: 1;  /*!< Timestamp Captured flag */
                uint16_t : 11;
            };
        };
    };
    struct {
        uint16_t dlc: 4;                            /*!< Data Length Code */
        uint16_t bitrate_switch: 1;                 /*!< Bit rate switch flag */
        uint16_t canfd_frame: 1;                    /*!< CANFD Frame flag */
        uint16_t : 2;
        uint16_t filter_index: 7;                   /*!< CAN filter index */
        uint16_t accepted_non_matching_frame: 1;    /*!< Accept non-matching Frame flag */
    };
    union {
        uint8_t data_8[64];                         /*!< Data buffer as byte array */
        uint32_t data_32[16];                       /*!< Data buffer as word array */
    };
} mcan_rx_message_t;

/**
 * @brief TX Event Fifo Element Structure
 */
typedef union mcan_tx_event_fifo_elem_struct {
    struct {
        /* First word */
        union {
            struct {
                uint32_t ext_id: 29;                    /*!< CAN Identifier */
                uint32_t rtr: 1;                        /*!< Remote Transmission Request */
                uint32_t extend_id: 1;                  /*!< Extended Identifier */
                uint32_t error_state_indicator: 1;      /*!< Error State Indicator */
            };
            struct {
                uint32_t : 18;
                uint32_t std_id: 11;
                uint32_t : 3;
            };
        };

        /* first 16-bit of the 2nd word */
        union {
            uint16_t tx_timestamp;                      /*!< Tx Timestamp */
            struct {
                uint16_t tx_timestamp_pointer: 4;       /*!< TX timestamp pointer */
                uint16_t tx_timestamp_captured: 1;      /*!< TX timestamp captured flag */
                uint16_t : 11;
            };
        };
        /* high-half 16-bit of the 2nd word */
        struct {
            uint16_t dlc: 4;                            /*!< Data length code */
            uint16_t bitrate_switch: 1;                 /*!< Bitrate Switch flag */
            uint16_t canfd_frame: 1;                    /*!< CANFD frame */
            uint16_t event_type: 2;                     /*!< Event type */
            uint16_t message_marker: 8;                 /*!< Message Marker */
        };
    };
    uint32_t words[2];
} mcan_tx_event_fifo_elem_t;



/**
 * @brief CAN Identifier Types
 */
#define MCAN_CAN_ID_TYPE_STANDARD (0U)      /*!< Standard Identifier */
#define MCAN_CAN_ID_TYPE_EXTENDED (1U)      /*!< Extended Identifier */

/**
 * @brief MCAN Filter Configuration
 */
typedef union mcan_filter_config_struct {
    struct {
        uint16_t list_start_addr;       /*!< List Start address (CAN Message Buffer Offset) */
        uint16_t list_size;             /*!< Element Count */
    };
    uint32_t reg_val;                   /*!< Register value */
} mcan_filter_config_t;

/**
 * @brief MCAN RXFIFO Configuration
 */
typedef union mcan_rxfifo_config_struct {
    struct {
        uint32_t start_addr: 16;        /*!< Start address (CAN Message Buffer Offset) */
        uint32_t fifo_size: 8;          /*!< FIFO element count */
        uint32_t watermark: 7;          /*!< FIFO watermark */
        uint32_t operation_mode: 1;     /*!< Operation mode */
    };
    uint32_t reg_val;                   /*!< Register value */
} mcan_rxfifo_config_t;

/**
 * @brief MCAN RXBUF Configuration
 */
typedef struct {
    uint32_t start_addr;                /*!< Start address (CAN Message Buffer Offset) */
} mcan_rxbuf_config_t;

/**
 * @brief MCAN Data Field Size Definitions
 */
#define MCAN_DATA_FIELD_SIZE_8BYTES     (0U)
#define MCAN_DATA_FIELD_SIZE_12BYTES    (1U)
#define MCAN_DATA_FIELD_SIZE_16BYTES    (2U)
#define MCAN_DATA_FIELD_SIZE_20BYTES    (3U)
#define MCAN_DATA_FIELD_SIZE_24BYTES    (4U)
#define MCAN_DATA_FIELD_SIZE_32BYTES    (5U)
#define MCAN_DATA_FIELD_SIZE_48BYTES    (6U)
#define MCAN_DATA_FIELD_SIZE_64BYTES    (7U)

/**
 * @brief MCAN FIFO Operation Mode types
 */
#define MCAN_FIFO_OPERATION_MODE_BLOCKING (0U)
#define MCAN_FIFO_OPERATION_MODE_OVERWRITE (1U)

/**
 * @brief  MCAN RXBUF or RXFIFO Element Configuration
 */
typedef union mcan_rx_fifo_or_buf_elem_config_struct {
    struct {
        uint32_t fifo0_data_field_size: 4;      /*!< FIFO0 data field size option */
        uint32_t fifo1_data_field_size: 4;      /*!< FIFO1 data field size option */
        uint32_t buf_data_field_size: 4;        /*!< Buffer Data field size option */
        uint32_t : 20;
    };
    uint32_t reg_val;                           /*!< Register value */
} mcan_rx_fifo_or_buf_elem_config_t;

/**
 * @brief MCAN TXBUF operation mode types
 */
#define MCAN_TXBUF_OPERATION_MODE_FIFO  (0U)
#define MCAN_TXBUF_OPERATION_MODE_QUEUE (1U)


typedef union mcan_txbuf_config_struct {
    struct {
        uint32_t start_addr: 16;                /*!< Start address (CAN Message Buffer Offset) */
        uint32_t dedicated_tx_buf_size: 6;      /*!< Dedicated TX buffer size */
        uint32_t : 2;
        uint32_t fifo_queue_size: 6;            /*!< FIFO or Queue Size */
        uint32_t tx_fifo_queue_mode: 1;         /*!< FIFO or Queue mode selection */
        uint32_t : 1;
    };
    uint32_t reg_val;                           /*!< register value */
} mcan_txbuf_config_t;

typedef struct mcan_txbuf_elem_config_struct {
    uint32_t data_field_size;                   /*!< Data Field size option */
} mcan_txbuf_elem_config_t;

/**
 * @brief MCAN TX Event FIFO Structure
 */
typedef union {
    struct {
        uint16_t start_addr;                    /*!< Start Address(CAN Message Buffer Offset */
        uint8_t fifo_size;                      /*!< FIFO element count */
        uint8_t fifo_watermark;                 /*!< FIFO watermark */
    };
    uint32_t reg_val;                           /*!< register value */
} mcan_tx_evt_fifo_config_t;

/**
 * @brief MCAN RAM Flexible Configuration
 *
 * @note This Configuration provides the full MCAN RAM configuration, this configuration is recommended only for
 *       experienced developers who is skilled at the MCAN IP
 */
typedef struct mcan_ram_flexible_config_struct {
    bool enable_std_filter;                             /*!< Enable Standard Identifier Filter */
    bool enable_ext_filter;                             /*!< Enable Extended Identifier Filter */
    bool enable_rxfifo0;                                /*!< Enable RXFIFO */
    bool enable_rxfifo1;                                /*!< Enable RXFIF1 */
    bool enable_rxbuf;                                  /*!< Enable RXBUF */
    bool enable_txbuf;                                  /*!< Enable TXBUF */
    bool enable_tx_evt_fifo;                            /*!< Enable TX Event FIFO */

    mcan_filter_config_t std_filter_config;             /*!< Standard Identifier Filter Configuration */
    mcan_filter_config_t ext_filter_config;             /*!< Extended Identifier Filter Configuration */

    mcan_txbuf_config_t txbuf_config;                   /*!< TXBUF Configuration */
    mcan_txbuf_elem_config_t txbuf_elem_config;         /*!< TXBUF Element Configuration */
    mcan_tx_evt_fifo_config_t tx_evt_fifo_config;       /*!< TX Event FIFO Configuration */

    mcan_rxfifo_config_t rxfifo0_config;                /*!< RXFIFO0 Configuration */
    mcan_rxfifo_config_t rxfifo1_config;                /*!< RXFIFO1 Configuration */
    mcan_rxbuf_config_t rxbuf_config;                   /*!< RXBUF Configuration */
    mcan_rx_fifo_or_buf_elem_config_t rx_elem_config;   /*!< RX Element Configuration */
} mcan_ram_flexible_config_t;

/**
 * @brief MCAN RAM configuration
 *
 * @note: This Configuration focuses on the minimum required information for MCAN RAM configuration
 *        The Start address of each BUF/FIFO will be automatically calculated by the MCAN Driver API
 *        This RAM configuration is recommended for the most developers
 */
typedef struct mcan_ram_config_struct {
    bool enable_std_filter;                             /*!< Enable Standard Identifier Filter */
    uint8_t std_filter_elem_count;                      /*!< Standard Identifier Filter Element Count */

    bool enable_ext_filter;                             /*!< Enable Extended Identifier Filter */
    uint8_t ext_filter_elem_count;                      /*!< Extended Identifier Filter Element Count */

    struct {
        uint32_t enable: 4;                            /*!< Enable Flag for RXFIFO */
        uint32_t elem_count: 8;                        /*!< Element Count for RXFIFO */
        uint32_t watermark: 8;                         /*!< Watermark for RXFIFO */
        uint32_t operation_mode: 4;                    /*!< Operation Mode for RXFIFO */
        uint32_t data_field_size: 8;                   /*!< Data field size option for RXFIFO */
    } rxfifos[2];

    bool enable_rxbuf;                                  /*!< Enable RXBUF */
    uint8_t rxbuf_elem_count;                           /*!< RXBUF Element count */
    uint16_t rxbuf_data_field_size;                     /*!< RXBUF Data Field Size option */

    bool enable_txbuf;                                  /*!< Enable TXBUF */
    uint8_t txbuf_data_field_size;                      /*!< TXBUF Data Field Size option */
    uint8_t txbuf_dedicated_txbuf_elem_count;           /*!< Dedicated TXBUF element count */
    uint8_t txbuf_fifo_or_queue_elem_count;             /*!< FIFO/Queue element count */
    uint8_t txfifo_or_txqueue_mode;                     /*!< TXFIFO/QUEUE mode */

    bool enable_tx_evt_fifo;                            /*!< Enable TX Event FIFO */
    uint8_t tx_evt_fifo_elem_count;                     /*!< TX Event FIFO Element count */
    uint8_t tx_evt_fifo_watermark;                      /*!< TX Event FIFO Watermark */
} mcan_ram_config_t;

/**
 * @brief MCAN Accept Non-Matching Frame options
 */
#define MCAN_ACCEPT_NON_MATCHING_FRAME_OPTION_IN_RXFIFO0 (0U)   /*!< Save non-matching frame to RXFIFO0 */
#define MCAN_ACCEPT_NON_MATCHING_FRAME_OPTION_IN_RXFIFO1 (1U)   /*!< Save non-matching frame to RXFIFO1 */
#define MCAN_ACCEPT_NON_MATCHING_FRAME_OPTION_REJECT (2U)       /*!< Reject non-matching frame */

/**
 * @brief MCAN Global CAN configuration
 */
typedef struct mcan_global_filter_config_struct {
    uint8_t accept_non_matching_std_frame_option;   /*!< Accept non-matching standard frame option */
    uint8_t accept_non_matching_ext_frame_option;   /*!< Accept non-matching extended frame option */
    bool reject_remote_std_frame;                   /*!< Reject Remote Standard Frame */
    bool reject_remote_ext_frame;                   /*!< Reject Remote Extended Frame */
} mcan_global_filter_config_t;

/**
 * @brief MCAN Filter type definitions
 */
#define MCAN_FILTER_TYPE_RANGE_FILTER (0U)              /*!< CAN Identifier Range filter */
#define MCAN_FILTER_TYPE_SPECIFIED_ID_FILTER (1U)       /*!< CAN Identifier ID filter */
#define MCAN_FILTER_TYPE_CLASSIC_FILTER (2U)            /*!< CAN classic filter */
#define MCAN_FILTER_TYPE_FILTER_DISABLED (3U)           /*!< CAN filter disabled */
#define MCAN_FILTER_TYPE_DUAL_ID_EXT_FILTER_IGNORE_MASK /*!< CAN Identifier Range filter, ignoring extended ID mask */

/**
 * @brief MCAN Filter Configuration Options
 */
#define MCAN_FILTER_ELEM_CFG_DISABLED (0)                                   /*!<  Disable Filter Element */
#define MCAN_FILTER_ELEM_CFG_STORE_IN_RX_FIFO0_IF_MATCH (1U)                /*!< Store data into RXFIFO0 if matching */
#define MCAN_FILTER_ELEM_CFG_STORE_IN_RX_FIFO1_IF_MATCH (2U)                /*!< Store data into RXFIFO1 if matching */
#define MCAN_FILTER_ELEM_CFG_REJECT_ID_IF_MATCH (3U)                        /*!< Reject ID if matching */
#define MCAN_FILTER_ELEM_CFG_SET_PRIORITY_IF_MATCH (4U)                     /*!< Set Priority if matching */
/*!< Set Priority and store into RXFIFO0 if matching */
#define MCAN_FILTER_ELEM_CFG_SET_PRIORITY_AND_STORE_IN_FIFO0_IF_MATCH (5U)
/*!< Set Priority and store into RXFIFO1 if matching */
#define MCAN_FILTER_ELEM_CFG_SET_PRIORITY_AND_STORE_IN_FIFO1_IF_MATCH (6U)
#define MCAN_FILTER_ELEM_CFG_STORE_INTO_RX_BUFFER_OR_AS_DBG_MSG (7U)        /*!< Store into RXBUF if matching */

/**
 * @brief MCAN Filter Element definitions
 */
typedef struct mcan_std_id_filter_elem_struct {
    uint8_t filter_type;            /*!< Filter type */
    uint8_t filter_config;          /*!< Filter configuration */
    uint8_t can_id_type;            /*!< CAN ID type */
    uint8_t sync_message;           /*!< Sync Message */
    union {
        /* This definition takes effect if the filter type is range filter */
        struct {
            uint32_t start_id;      /*!< Start of ID range */
            uint32_t end_id;        /*!< End of ID range */
        };
        /* This definition takes effect if the filter type is dual id filter */
        struct {
            uint32_t id1;           /*!< ID1 */
            uint32_t id2;           /*!< ID2 */
        };
        /* This definition takes effect if the filter type is classic filter */
        struct {
            uint32_t filter_id;     /*!< Filter ID */
            uint32_t filter_mask;   /*!< Filter Mask */
        };
        /* This definition takes effect if the filter configuration is "store into RX Buffer or as debug message"
         *
         *  In this definition, only the exact ID matching mode is activated
         */
        struct {
            uint32_t match_id;          /*!< Matching ID */
            uint32_t offset: 6;         /*!< RX Buffer Index */
            uint32_t filter_event: 3;   /*!< Filter event, set to 0 */
            uint32_t store_location: 2; /*!< Store location, 0 - RX buffer */
            uint32_t : 21;
        };
    };
} mcan_filter_elem_t;

/**
 * @brief MCAN Filter Element List structure
 */
typedef struct mcan_filter_elem_list_struct {
    uint32_t mcan_filter_elem_count;            /*!< Number of Filter element */
    const mcan_filter_elem_t *filter_elem_list; /*!< Filter element list */
} mcan_filter_elem_list_t;

/**
 * @brief MCAN Configuration for all filters
 *
 * @note The MCAN RAM related settings are excluded
 */
typedef struct mcan_all_filters_config_struct {
    mcan_global_filter_config_t global_filter_config;   /*!< Global Filter configuration */
    uint32_t ext_id_mask;                               /*!< Extended ID mask */
    mcan_filter_elem_list_t std_id_filter_list;         /*!< Standard Identifier Configuration List */
    mcan_filter_elem_list_t ext_id_filter_list;         /*!< Extended Identifier Configuration List */
} mcan_all_filters_config_t;

/**
 * @brief CAN Node Mode types
 */
typedef enum mcan_node_mode_enum {
    mcan_mode_normal = 0,               /*!< CAN works in normal mode */
    mcan_mode_loopback_internal = 1,    /*!< CAN works in internal loopback mode */
    mcan_mode_loopback_external = 2,    /*!< CAN works in external loopback mode */
    mcan_mode_listen_only = 3,          /*!< CAN works in listen-only mode */
} mcan_node_mode_t;

/**
 * @brief MCAN Timestamp Value
 */
typedef struct mcan_timestamp_value_struct {
    bool is_16bit;                  /*!< Timestamp is 16-bit */
    bool is_32bit;                  /*!< Timestamp is 32-bit */
    bool is_64bit;                  /*!< Timestamp is 64-bit */
    bool is_empty;                  /*!< Timestamp is empty */
    union {
        uint16_t ts_16bit;          /*!< 16-bit timestamp value */
        uint32_t ts_32bit;          /*!< 32-bit timestamp value */
        uint64_t ts_64bit;          /*!< 64-bit timestamp value */
        uint32_t words[2];          /*!< timestamp words */
    };
} mcan_timestamp_value_t;

/**
 * @brief MCAN TSU Configuration
 */
typedef struct mcan_tsu_config_struct {
    uint16_t prescaler;             /*!< Prescaler for MCAN clock, Clock source: AHB clock */
    bool capture_on_sof;            /*!< Capture On SOF, true - Capture on SOF, false - Capture on EOF */
    bool use_ext_timebase;          /*!< Use External Timebase */
    uint8_t ext_timebase_src;       /*!< External Timebase source, see the hpm_mcan_soc.h for more details */
    uint8_t tbsel_option;           /*!< Timebase selection option, see the hpm_mcan_soc.h for more details */
    bool enable_tsu;                /*!< Enable Timestamp Unit */
    bool enable_64bit_timestamp;    /*!< Enable 64bit Timestamp */
} mcan_tsu_config_t;

/**
 * @brief MCAN Timestamp Select
 */
#define MCAN_TIMESTAMP_SEL_MIN               (0U)
#define MCAN_TIMESTAMP_SEL_VALUE_ALWAYS_ZERO (0U)     /*!< Timestamp value always equal to 0 */
#define MCAN_TIMESTAMP_SEL_VALUE_INCREMENT   (1U)     /*!< Timestamp value increments according to prescaler */
#define MCAN_TIMESTAMP_SEL_EXT_TS_VAL_USED   (2U)     /*!< External Timestamp value used */
#define MCAN_TIMESTAMP_SEL_MAX               (MCAN_TIMESTAMP_SEL_EXT_TS_VAL_USED)

/**
 * @brief MCAN Internal timestamp configuration
 */
typedef struct mcan_internal_timestamp_config_struct {
    uint8_t counter_prescaler;          /*!< Timestamp Counter Prescaler, clock source: AHB clock */
    uint8_t timestamp_selection;        /*!< Timestamp Select */
} mcan_internal_timestamp_config_t;

/**
 * @brief MCAN Timeout Selection Options
 */
typedef enum mcan_timeout_sel_enum {
    mcan_timeout_continuous_operation     = 0,  /*!< Continuously count down timeout after writing to TOCV register */
    mcan_timeout_triggered_by_tx_evt_fifo = 1,  /*!< Count down if the TX EVT FIFO is not empty */
    mcan_timeout_triggered_by_rx_fifo0    = 2,  /*!< Count down if the RX FIFO0 is not empty */
    mcan_timeout_triggered_by_rx_fifo1    = 3,  /*!< Count down if the RX FIFO1 is not empty */
} mcan_timeout_sel_t;

/**
 * @brief MCAN Timeout configuration structure
 */
typedef struct mcan_timeout_config_struct {
    bool enable_timeout_counter;        /*!< Enable Timeout Counter */
    mcan_timeout_sel_t timeout_sel;     /*!< Timeout source selection */
    uint16_t timeout_period;            /*!< Timeout period */
} mcan_timeout_config_t;

/**
 * @brief MCAN Transmitter Delay Compensation Configuration
 */
typedef struct mcan_tdc_config_t {
    uint8_t ssp_offset;                 /*!< SSP offset */
    uint8_t filter_window_length;       /*!< Filter Window Length */
} mcan_tdc_config_t;


/**
 * @brief MCAN Configuration Structure
 */
typedef struct mcan_config_struct {
    union {
        /* This struct takes effect if "use_lowlevel_timing_setting = false" */
        struct {
            uint32_t baudrate;                      /*!< CAN 2.0 baudrate/CAN-FD Nominal Baudrate, in terms of bps */
            uint32_t baudrate_fd;                   /*!< CANFD data baudrate, in terms of bps */
            uint16_t can20_samplepoint_min;         /*!< Value = Minimum CAN2.0 sample point * 10 */
            uint16_t can20_samplepoint_max;         /*!< Value = Maximum CAN2.0 sample point * 10 */
            uint16_t canfd_samplepoint_min;         /*!< Value = Minimum CANFD sample point * 10 */
            uint16_t canfd_samplepoint_max;         /*!< Value = Maximum CANFD sample point * 10 */
        };
        /* This struct takes effect if "use_lowlevel_timing_setting = true" */
        struct {
            mcan_bit_timing_param_t can_timing;     /*!< CAN2.0/CANFD nominal timing setting */
            mcan_bit_timing_param_t canfd_timing;   /*!< CANFD data timing setting */
        };
    };
    bool use_lowlevel_timing_setting;               /*!< Use Low-level timing setting */
    mcan_node_mode_t mode;                          /*!< CAN node mode */
    bool enable_non_iso_mode;                       /*!< Enable Non-ISO FD mode */
    bool enable_transmit_pause;                     /*!< Enable Transmit Pause */
    bool enable_edge_filtering;                     /*!< Enable Edge Filtering */
    bool disable_protocol_exception_handling;       /*!< Disable Protocol Exception Handling */
    bool enable_wide_message_marker;                /*!< Enable Wide Message Marker */
    bool use_timestamping_unit;                     /*!< Use external Timestamp Unit */
    bool enable_canfd;                              /*!< Enable CANFD mode */
    bool enable_tdc;                                /*!< Enable transmitter delay compensation */
    bool enable_restricted_operation_mode;          /*!< Enable Restricted Operation Mode: Receive only */
    bool disable_auto_retransmission;               /*!< Disable auto retransmission */
    mcan_tdc_config_t tdc_config;                   /*!< Transmitter Delay Compensation Configuration */
    mcan_internal_timestamp_config_t timestamp_cfg; /*!< Internal Timestamp Configuration */
    mcan_tsu_config_t tsu_config;                   /*!< TSU configuration */
    mcan_ram_config_t ram_config;                   /*!< MCAN RAM configuration */
    mcan_all_filters_config_t all_filters_config;   /*!< All Filter configuration */

    mcan_timeout_config_t timeout_cfg;              /*!< Timeout configuration */

    uint32_t interrupt_mask;                        /*!< Interrupt Enable mask */
    uint32_t txbuf_trans_interrupt_mask;            /*!< Tx Buffer Transmission Interrupt Enable mask */
    uint32_t txbuf_cancel_finish_interrupt_mask;    /*!< TX Buffer Cancellation Finished Interrupt Enable Mask */
} mcan_config_t;

/**
 * @brief MCAN Timeout Selection Options
 */
#define MCAN_TIMEOUT_SEL_TYPE_CONTINUOUS_OPERATION (0U)
#define MCAN_TIMEOUT_SEL_TYPE_TIMEOUT_CTRL_BY_TX_EVT_FIFO (1U)
#define MCAN_TIMEOUT_SEL_TYPE_TIMEOUT_CTRL_BY_RX_FIFO0 (2U)
#define MCAN_TIMEOUT_SEL_TYPE_TIMEOUT_CTRL_BY_RX_FIFO1 (3U)

/**
 * @brief MCAN Timeout Counter Configuration
 */
typedef struct mcan_timeout_counter_config_struct {
    bool enable_timeout_counter;            /*!< Enable Timeout counter */
    uint8_t timeout_selection;              /*!< Timeout source selection */
    uint16_t timeout_period;                /*!< Timeout period */
} mcan_timeout_counter_config_t;

/**
 * @brief MCAN Error Count Information
 */
typedef struct mcan_error_count_struct {
    uint8_t transmit_error_count;       /*!< Transmit Error Count */
    uint8_t receive_error_count;        /*!< Receive Error Count */
    bool receive_error_passive;         /*!< The Receive Error Counter has reached the error passive level */
    uint8_t can_error_logging_count;    /*!< CAN Error Logging count */
} mcan_error_count_t;

/**
 * @brief MCAN Protocol Status
 */
typedef struct mcan_protocol_status {
    uint8_t tdc_val;                            /*!< Transmitter Delay Compensation Value */
    mcan_activity_state_t activity;             /*!< Current communication state */
    mcan_last_err_code_t last_error_code;       /*!< Last Error code */
    bool protocol_exception_evt_occurred;       /*!< Protocol Exception Event occurred */
    bool canfd_msg_received;                    /*!< CANFD message was received */
    bool brs_flag_set_in_last_rcv_canfd_msg;    /*!< Bitrate Switch bit is set in last received CANFD message */
    bool esi_flag_set_in_last_rcv_canfd_msg;    /*!< Error State Indicator bit is set in last received CANFD message */
    bool in_bus_off_state;                      /*!< Node is in bus-off state */
    bool in_warning_state;                      /*!< Node is in warning state */
    bool in_error_passive_state;                /*!< Node is in error passive state */
} mcan_protocol_status_t;

/**
 * @brief MCAN Message Storage Indicator Types
 */
#define MCAN_MESSAGE_STORAGE_INDICATOR_NO_FIFO_SELECTED     (0U)
#define MCAN_MESSAGE_STORAGE_INDICATOR_FIFO_MESSAGE_LOST    (1U)
#define MCAN_MESSAGE_STORAGE_INDICATOR_RXFIFO0              (2U)
#define MCAN_MESSAGE_STORAGE_INDICATOR_RXFIFO1              (3U)

/**
 * @brief MCAN High Priority Message Status Information
 */
typedef struct mcan_high_priority_message_status_struct {
    uint8_t filter_list_type;                            /*!< Filter List Type, 0 - STD filter, 1 - EXT filter */
    uint8_t filter_index;                                /*!< Filter Elem List */
    uint8_t message_storage_indicator;                   /*!< Message Storage Indicator */
    uint8_t buffer_index;
} mcan_high_priority_message_status_t;

/**
 * @brief Enable Transmit Pause
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_transmit_pause(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_TXP_MASK;
}

/**
 * @brief Disable Transmit Pause
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_transmit_pause(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_TXP_MASK;
}

/**
 * @brief Enable Edge Filtering
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_edge_filtering(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_EFBI_MASK;
}

/**
 * @brief Disable Edge Filtering
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_edge_filtering(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_EFBI_MASK;
}

/**
 * @brief Enable Protocol Exception Handling
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_protocol_exception_handling(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_PXHD_MASK;
}

/**
 * @brief Disable Protocol Exception Handling
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_protocol_exception_handling(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_PXHD_MASK;
}

/**
 * @brief Enable Wide Message Marker
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_wide_message_marker(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_WMM_MASK;
}

/**
 * @brief Disable Wide Message Marker
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_wide_message_marker(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_WMM_MASK;
}

/**
 * @brief Enable External Timestamp Unit
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_tsu(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_UTSU_MASK;
}

/**
 * @brief Disable External Timestamp Unit
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_tsu(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_UTSU_MASK;
}

/**
 * @brief Check whether TSU is used
 * @param [in] ptr MCAN base
 * @retval true if TSU is used
 * @retval false if TSU is not used
 */
static inline bool mcan_is_tsu_used(MCAN_Type *ptr)
{
    return ((ptr->CCCR & MCAN_CCCR_UTSU_MASK) != 0U);
}

/**
 * @brief Check whether 64-bit TSU timestamp is used
 * @param [in] ptr MCAN base
 * @retval true if 64-bit timestamp is used
 * @retval false if 32-bit timestamp is used
 */
static inline bool mcan_is_64bit_tsu_timestamp_used(MCAN_Type *ptr)
{
    return ((ptr->TSCFG & MCAN_TSCFG_EN64_MASK) != 0U);
}

/**
 * @brief Enable Bit Rate Switch
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_bitrate_switch(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_BRSE_MASK;
}

/**
 * @brief Disable Bit Rate Switch
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_bitrate_switch(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_BRSE_MASK;
}

/**
 * @brief Enable Auto Retransmission
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_auto_retransmission(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_DAR_MASK;
}

/**
 * @brief Disable Auto Transmission
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_auto_retransmission(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_DAR_MASK;
}

/**
 * @brief Enable Bus monitoring Mode
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_bus_monitoring_mode(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_MON_MASK;
}

/**
 * @brief Stop MCAN clock
 * @param [in] ptr MCAN base
 */
static inline void mcan_stop_clock(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_CSR_MASK;
}

/**
 * @brief Enable MCAN clock
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_clock(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_CSR_MASK;
}

static inline bool mcan_is_clock_enabled(MCAN_Type *ptr)
{
    return ((ptr->CCCR & MCAN_CCCR_CSR_MASK) == 0UL);
}

/**
 * @brief Disable Bus monitoring Mode
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_bus_monitoring_mode(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_MON_MASK;
}

/**
 * @brief Check whether CAN clock is stopped or not
 * @param [in] ptr MCAN base
 */
static inline bool mcan_is_clock_stopped(MCAN_Type *ptr)
{
    return ((ptr->CCCR & MCAN_CCCR_CSA_MASK) != 0U);
}

/**
 * @brief Enable Restricted Operation Mode
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_restricted_operation_mode(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_ASM_MASK;
}

/**
 * @brief Disable Restricted Operation Mode
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_restricted_operation_mode(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_ASM_MASK;
}

/**
 * @brief Enable Write Access to Protected Configuration Registers
 * @param [in] ptr MCAN base
 */
static inline void mcan_enable_write_to_prot_config_registers(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_CCE_MASK;
}

/**
 * @brief Disable Write Access to Protected Configuration Registers
 * @param [in] ptr MCAN base
 */
static inline void mcan_disable_write_to_prot_config_registers(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_CCE_MASK;
}

/**
 * @brief Get Timestamp Counter Value
 * @param [in] ptr MCAN base
 * @return timestamp value
 */
static inline uint16_t mcan_get_timestamp_counter_value(MCAN_Type *ptr)
{
    return ptr->TSCV;
}

/**
 * @brief Switch MCAN to Initialization mode
 * @param [in] ptr MCAN base
 */
static inline void mcan_enter_init_mode(MCAN_Type *ptr)
{
    ptr->CCCR |= MCAN_CCCR_INIT_MASK;
}

/**
 * @brief Switch MCAN to Normal mode
 * @param [in] ptr MCAN base
 */
static inline void mcan_enter_normal_mode(MCAN_Type *ptr)
{
    ptr->CCCR &= ~MCAN_CCCR_INIT_MASK;
}

/**
 * @brief Get Timeout value
 * @param [in] ptr MCAN base
 * @return timeout value
 */
static inline uint16_t mcan_get_timeout_counter_value(MCAN_Type *ptr)
{
    return ptr->TOCV;
}

/**
 * @brief Reset Timeout counter value
 *
 * @param [in] ptr MCAN base
 */
static inline void mcan_reset_timeout_counter_value(MCAN_Type *ptr)
{
    *((volatile uint32_t *) &ptr->TOCV) = 0;
}

/**
 * @brief Get Error Counter Information
 * @param [in] ptr MCAN base
 * @param [out] err_cnt Error Count buffer
 */
static inline void mcan_get_error_counter(MCAN_Type *ptr, mcan_error_count_t *err_cnt)
{
    uint32_t ecr = ptr->ECR;
    err_cnt->transmit_error_count = MCAN_ECR_TEC_GET(ecr);
    err_cnt->receive_error_count = MCAN_ECR_REC_GET(ecr);
    err_cnt->receive_error_passive = (MCAN_ECR_RP_GET(ecr) == 1U);
    err_cnt->can_error_logging_count = MCAN_ECR_CEL_GET(ecr);
}

/**
 * @brief Get Last Error Code
 * @param [in] ptr MCAN base
 * @return Last Error code
 */
static inline uint8_t mcan_get_last_error_code(MCAN_Type *ptr)
{
    return MCAN_PSR_LEC_GET(ptr->PSR);
}

/**
 * @brief Get Last Data Phase Error Code
 * @param [in] ptr MCAN base
 * @return Last Error Code in Data phase
 */
static inline uint8_t mcan_get_last_data_error_code(MCAN_Type *ptr)
{
    return MCAN_PSR_DLEC_GET(ptr->PSR);
}

/**
 * @brief Get CAN Activity
 * @param [in] ptr MCAN base
 * @return  CAN IP activity
 */
static inline uint8_t mcan_get_activity(MCAN_Type *ptr)
{
    return MCAN_PSR_ACT_GET(ptr->PSR);
}

/**
 * @brief Check whether the CAN node is under error passive state
 * @param [in] ptr MCAN base
 * @return true is CAN is under error passive state
 */
static inline bool mcan_is_in_err_passive_state(MCAN_Type *ptr)
{
    return (MCAN_PSR_EP_GET(ptr->PSR) == 1U);
}

/**
 * @brief Check whether the CAN mode is under Warning State
 * @param [in] ptr MCAN base
 * @return true if the CAN node is under Error Warning State
 */
static inline bool mcan_is_in_error_warning_state(MCAN_Type *ptr)
{
    return (MCAN_PSR_EW_GET(ptr->PSR) == 1U);
}

/**
 * @brief Check whether the CAN node is under Bus-off state
 * @param [in] ptr MCAN base
 * @return true if the CAN node is under Bus-off state
 */
static inline bool mcan_is_in_busoff_state(MCAN_Type *ptr)
{
    return (MCAN_PSR_BO_GET(ptr->PSR) == 1U);
}

/**
 * @brief Get the Last Data Phase Error
 * @param [in] ptr MCAN base
 * @deprecated This API will be removed in later SDK release
 * @return  The last Data Phase Error
 */
static inline uint8_t mcan_get_data_phase_last_error_code(MCAN_Type *ptr)
{
    return MCAN_PSR_DLEC_GET(ptr->PSR);
}

/**
 * @brief Check Whether the Error Status Indicator Flag is set in the last received CANFD message
 * @param [in] ptr MCAN base
 * @return true if the Error Status Indicator Flag is set in the last received CANFD Message
 */
static inline bool mcan_is_error_state_indicator_flag_set_in_last_received_canfd_msg(MCAN_Type *ptr)
{
    return (MCAN_PSR_RESI_GET(ptr->PSR) == 1U);
}

/**
 * @brief Check whether the Bitrate Switch Flag is set in the last received CANFD message
 * @param [in] ptr MCAN base
 * @return true if Bit rate switch flag is set in the last received CANFD message
 */
static inline bool mcan_is_bitrate_switch_flag_set_in_last_received_canfd_msg(MCAN_Type *ptr)
{
    return (MCAN_PSR_RBRS_GET(ptr->PSR) == 1U);
}

/**
 * @brief Check whether CANFD messages were received
 * @param [in] ptr MCAN base
 * @return true if a CANFD message was received
 */
static inline bool mcan_is_canfd_message_received(MCAN_Type *ptr)
{
    return (MCAN_PSR_RFDF_GET(ptr->PSR) == 1U);
}

/**
 * @brief Check whether Protocol Exception Events were occurred
 * @param [in] ptr MCAN base
 * @return true if Protocol Exception Events were occurred
 */
static inline bool mcan_is_protocol_exception_event_occurred(MCAN_Type *ptr)
{
    return (MCAN_PSR_PXE_GET(ptr->PSR) == 1U);
}

/**
 * @brief Get the Transmitter Delay Compensation Value
 * @param [in] ptr MCAN base
 * @return Transmitter Delay Compensation value
 */
static inline uint8_t mcan_get_transmitter_delay_compensation_value(MCAN_Type *ptr)
{
    return MCAN_PSR_TDCV_GET(ptr->PSR);
}

/**
 * @brief Get Interrupt Flags
 * @param [in] ptr MCAN base
 * @return Interrupt Flags
 */
static inline uint32_t mcan_get_interrupt_flags(MCAN_Type *ptr)
{
    return ptr->IR;
}

/**
 * @brief Clear Interrupt Flags
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt Mask
 */
static inline void mcan_clear_interrupt_flags(MCAN_Type *ptr, uint32_t mask)
{
    ptr->IR = mask;
}

/**
 * @brief Enable Interrupts
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt mask
 */
static inline void mcan_enable_interrupts(MCAN_Type *ptr, uint32_t mask)
{
    ptr->ILS &= ~mask;
    ptr->IE |= mask;
    ptr->ILE = 1U;
}

/**
 * @brief Enable TXBUF Interrupt
 * @deprecated This API is deprecated, will be removed in later SDK release
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt mask
 */
static inline void mcan_enable_txbuf_interrupt(MCAN_Type *ptr, uint32_t mask)
{
    ptr->TXBTIE |= mask;
}

/**
 * @brief Disable TXBUF Interrupt
 * @deprecated This API is deprecated, will be removed in later SDK release
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt mask
 */
static inline void mcan_disable_txbuf_interrupt(MCAN_Type *ptr, uint32_t mask)
{
    ptr->TXBTIE &= ~mask;
}

/**
 * @brief Disable Interrupts
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt mask
 */
static inline void mcan_disable_interrupts(MCAN_Type *ptr, uint32_t mask)
{
    ptr->IE &= ~mask;
}

/**
 * @brief Enable TXBUF Transmission interrupt
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt mask
 */
static inline void mcan_enable_txbuf_transmission_interrupt(MCAN_Type *ptr, uint32_t mask)
{
    ptr->TXBTIE |= mask;
}

/**
 * @brief Disable TXBUF Transmission interrupt
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt mask
 */
static inline void mcan_disable_txbuf_transmission_interrupt(MCAN_Type *ptr, uint32_t mask)
{
    ptr->TXBTIE &= ~mask;
}

/**
 * @brief Enable TXBUF Cancellation Finish interrupt
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt mask
 */
static inline void mcan_enable_txbuf_cancel_finish_interrupt(MCAN_Type *ptr, uint32_t mask)
{
    ptr->TXBCIE |= mask;
}

/**
 * @brief Disable TXBUF Cancellation Finish interrupt
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt mask
 */
static inline void mcan_disable_txbuf_cancel_finish_interrupt(MCAN_Type *ptr, uint32_t mask)
{
    ptr->TXBCIE &= ~mask;
}

/**
 * @brief Select Interrupt Line
 * @param [in] ptr MCAN base
 * @param [in] mask Interrupt mask
 * @param [in] line_index Interrupt Line Index
 */
static inline void mcan_interrupt_line_select(MCAN_Type *ptr, uint32_t mask, uint8_t line_index)
{
    if (line_index == 0) {
        ptr->ILS &= ~mask;
    } else {
        ptr->ILS |= mask;
    }
    ptr->ILE = (1UL << line_index);
}

/**
 * @brief Check whether a TXFIFO/TXBUF transmission request is pending
 * @param [in] ptr CAN Base
 * @param [in] index TXBUF/TXFIFO Index
 * @return True is the specified TXFIFO/TXBUF Transmission request is pending
 */
static inline bool mcan_is_transmit_request_pending(MCAN_Type *ptr, uint32_t index)
{
    return ((ptr->TXBRP & ((1UL << index))) != 0U);
}

/**
 * @brief Check whether TXFIFO is full
 * @param [in] ptr MCAN base
 * @return true if TXFIFO is full
 */
static inline bool mcan_is_txfifo_full(MCAN_Type *ptr)
{
    return ((ptr->TXFQS & MCAN_TXFQS_TFQF_MASK) != 0U);
}

/**
 * @brief Get the TXFIFO Put Index
 * @param [in] ptr MCAN base
 * @return The TX FIFO Put Index
 */
static inline uint32_t mcan_get_txfifo_put_index(MCAN_Type *ptr)
{
    return MCAN_TXFQS_TFQPI_GET(ptr->TXFQS);
}

/**
 * @brief Request A Transmission via specified TXBUF Index
 * @param [in] ptr MCAN Base
 * @param [in] index TXBUF index
 */
static inline void mcan_send_add_request(MCAN_Type *ptr, uint32_t index)
{
    ptr->TXBAR = (1UL << index);
}

/**
 * @brief Request several transmission via specified TXBUF/FIFO Bit masks
 *        MCAN IP will transmit data in the buffer if corresponding bit in index_bitmask is asserted
 * @param [in] ptr MCAN Base
 * @param [in] index_bitmask TXFIFO/BUF bit masks
 */
static inline void mcan_send_add_multiple_requests(MCAN_Type *ptr, uint32_t index_bitmask)
{
    ptr->TXBAR = index_bitmask;
}

/**
 * @brief Cancel the TXBUF Send request
 * @param [in] ptr MCAN Base
 * @param [in] index TXBUF index
 */
static inline void mcan_cancel_tx_buf_send_request(MCAN_Type *ptr, uint32_t index)
{
    ptr->TXBCR = (1UL << index);
}

/**
 * @brief Check whether the Transmission completed via specified TXBUF/TXFIFO
 * @param [in] ptr MCAN base
 * @param [in] index TXBUF Index
 * @return True is the Transmission completed via specified TXBUF
 */
static inline bool mcan_is_transmit_occurred(MCAN_Type *ptr, uint32_t index)
{
    return ((ptr->TXBTO & (1UL << index)) != 0U);
}

/**
 * @brief Check Whether there are data available in specified RXBUF
 * @param [in] ptr MCAN Base
 * @param [in] index  RXBUF index
 * @return True if there are data available
 */
static inline bool mcan_is_rxbuf_data_available(MCAN_Type *ptr, uint32_t index)
{
    bool result;
    if (index < 32U) {
        result = (ptr->NDAT1 & (1UL << index)) != 0U;
    } else if (index < 64U) {
        result = (ptr->NDAT2 & (1UL << (index - 32U))) != 0U;
    } else {
        result = false;
    }
    return result;
}

/**
 * @brief Clear RXBUF Data available Flag for specified RXBUF
 * @param [in] ptr MCAN base
 * @param [in] index RXBUF index
 */
static inline void mcan_clear_rxbuf_data_available_flag(MCAN_Type *ptr, uint32_t index)
{
    if (index < 32U) {
        ptr->NDAT1 = (1UL << index);
    } else if (index < 64U) {
        ptr->NDAT2 = (1UL << (index - 32U));
    } else {
        /* Do nothing */
    }
}

/**
 * @brief Check whether specified Interrupt is set
 * @param [in] ptr MCAN Base
 * @param [in] mask Interrupt Flags
 * @retval true if corresponding bits are set
 */
static inline bool mcan_is_interrupt_flag_set(MCAN_Type *ptr, uint32_t mask)
{
    return ((ptr->IR & mask) != 0U);
}

/**
 * @brief Check whether the TSU timestamp is available
 *
 * @param [in] ptr MCAN base
 * @param [in] index Timestamp pointer
 * @retval true TSU Timestamp is available
 * @retval false TSU timestamp is unavailable
 */
static inline bool mcan_is_tsu_timestamp_available(MCAN_Type *ptr, uint32_t index)
{
    bool is_available = false;
    if (index < ARRAY_SIZE(ptr->TS_SEL)) {
        is_available = ((ptr->TSS1 & (1UL << index)) != 0U);
    }
    return is_available;
}

/**
 * @brief Read 32bit Timestamp value from TSU
 * @param [in] ptr MCAN Base
 * @param [in] index Timestamp pointer
 * @return Timestamp value
 */
uint32_t mcan_read_32bit_tsu_timestamp(MCAN_Type *ptr, uint32_t index);

/**
 * @brief Read 64bit Timestamp value from TSU
 * @param [in] ptr MCAN Base
 * @param [in] index Timestamp pointer
 * @return Timestamp value
 */
uint64_t mcan_read_64bit_tsu_timestamp(MCAN_Type *ptr, uint32_t index);

/**
 * @brief Get High Priority Message Status
 * @param [in] ptr MCAN base
 * @param [out] status Pointer to High Priority Message Status Buffer
 */
void mcan_get_high_priority_message_status(MCAN_Type *ptr, mcan_high_priority_message_status_t *status);

/**
 * @brief Get Default CAN configuration
 * @param [in] ptr MCAN base
 * @param [out] config CAN configuration
 */
void mcan_get_default_config(MCAN_Type *ptr, mcan_config_t *config);

/**
 * @brief Get message Size from Data Length Code
 * @param [in] dlc Data Length Code
 * @return Message Size in Bytes
 */
uint8_t mcan_get_message_size_from_dlc(uint8_t dlc);

/**
 * @brief Get the Data field size from data field size option
 *
 * @param [in] data_field_size_option Data size option
 * @return data field size in bytes
 */
uint8_t mcan_get_data_field_size(uint8_t data_field_size_option);

/**
 * @brief Get Default Full MCAN RAM configuration
 * If the device is configured as classic CAN node, the default CAN RAM settings are as below:
 *  - Standard Identifier Filter Elements: 32
 *  - Extended Identifier Filter Elements: 32
 *  - TXBUF Elements Info:
 *      - Element Count:32
 *      - Dedicated TXBUF element count: 16
 *      - TXFIFO/QQueue element count: 16
 *      - Data Field Size: 8
 *      .
 *   - RXFIFO0 Elements Info:
 *      - Element Count :32
 *      - Data Field Size: 8
 *      .
 *   - RXFIFO1 Elements Info:
 *      - Element Count : 32
 *      - Data Field Size: 8
 *      .
 *    - RXBUF Element Info:
 *      - Element Count: 16
 *      - Data Field Size : 8
 *      .
 *    - TX Event FIFO Element Count: 32
 *  .
 * If the device is configured as CANFD node, the default CAN RAM settings are as below:
 *  - Standard Identifier Filter Elements: 16
 *  - Extended Identifier Filter Elements: 16
 *  - TXBUF Elements Info:
 *      - Element Count:8
 *      - Dedicated TXBUF element count: 4
 *      - TXFIFO/QQueue element count: 4
 *      - Data Field Size: 64
 *      .
 *   - RXFIFO0 Elements Info:
 *      - Element Count : 8
 *      - Data Field Size: 64
 *      .
 *   - RXFIFO1 Elements Info:
 *      - Element Count : 8
 *      - Data Field Size: 64
 *      .
 *    - RXBUF Element Info:
 *      - Element Count: 4
 *      - Data Field Size : 64
 *      .
 *    - TX Event FIFO Element Count: 8
 *    .
 * @param [in] ptr MCAN base
 * @param [out] ram_config CAN RAM Configuration
 * @param [in] enable_canfd CANFD enable flag
 */
void mcan_get_default_ram_flexible_config(MCAN_Type *ptr, mcan_ram_flexible_config_t *ram_config, bool enable_canfd);

/**
 * @brief Get Default MCAN RAM configuration
 * If the device is configured as classic CAN node, the default CAN RAM settings are as below:
 *  - Standard Identifier Filter Elements: 32
 *  - Extended Identifier Filter Elements: 32
 *  - TXBUF Elements Info:
 *      - Element Count:32
 *      - Dedicated TXBUF element count: 16
 *      - TXFIFO/QQueue element count: 16
 *      - Data Field Size: 8
 *      .
 *   - RXFIFO0 Elements Info:
 *      - Element Count :32
 *      - Data Field Size: 8
 *      .
 *   - RXFIFO1 Elements Info:
 *      - Element Count : 32
 *      - Data Field Size: 8
 *      .
 *    - RXBUF Element Info:
 *      - Element Count: 16
 *      - Data Field Size : 8
 *      .
 *    - TX Event FIFO Element Count: 32
 *    .
 * If the device is configured as CANFD node, the default CAN RAM settings are as below:
 *  - Standard Identifier Filter Elements: 16
 *  - Extended Identifier Filter Elements: 16
 *  - TXBUF Elements Info:
 *      - Element Count:8
 *      - Dedicated TXBUF element count: 4
 *      - TXFIFO/QQueue element count: 4
 *      - Data Field Size: 64
 *      .
 *   - RXFIFO0 Elements Info:
 *      - Element Count : 8
 *      - Data Field Size: 64
 *      .
 *   - RXFIFO1 Elements Info:
 *      - Element Count : 8
 *      - Data Field Size: 64
 *      .
 *    - RXBUF Element Info:
 *      - Element Count: 4
 *      - Data Field Size : 64
 *      .
 *    - TX Event FIFO Element Count: 8
 *    .
 * @param [in] ptr MCAN base
 * @param [out] simple_config Simple CAN RAM Configuration
 * @param [in] enable_canfd CANFD enable flag
 */
void mcan_get_default_ram_config(MCAN_Type *ptr, mcan_ram_config_t *simple_config, bool enable_canfd);

/**
 * @brief Initialize CAN controller
 * @param [in] ptr MCAN base
 * @param [in] config CAN configuration
 * @param [in] src_clk_freq CAN clock frequency
 * @retval status_success if operation is successful
 * @retval status_invalid_argument if any parameters are invalid
 */
hpm_stat_t mcan_init(MCAN_Type *ptr, mcan_config_t *config, uint32_t src_clk_freq);

/**
 * @brief De-Initialize CAN controller
 *
 * @param [in] ptr MCAN base
 */
void mcan_deinit(MCAN_Type *ptr);

/**
 * @brief Configure MCAN RAM will Full RAM configuration
 * @param [in] ptr MCAN base
 * @param [in] config MCAN RAM Full Configuration
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_config_ram_with_flexible_config(MCAN_Type *ptr, mcan_ram_flexible_config_t *config);

/**
 * @brief Configure MCAN RAM will Simplified RAM configuration
 * @param [in] ptr MCAN base
 * @param [in] config MCAN RAM configuration
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_config_ram(MCAN_Type *ptr, mcan_ram_config_t *config);

/**
 * @brief Configure All CAN filters
 * @param [in] ptr MCAN base
 * @param [in] config All CAN Filter configuration
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_config_all_filters(MCAN_Type *ptr, mcan_all_filters_config_t *config);

/**
 * @brief Configure Transmitter Delay Compensation
 * @param [in] ptr MCAN base
 * @param [in] config Transmitter Delay compensation configure
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_config_transmitter_delay_compensation(MCAN_Type *ptr, mcan_tdc_config_t *config);

/**
 * @brief Configure Global Filter
 * @param [in] ptr MCAN base
 * @param [in] filter_config Global Filter Configuration
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_set_global_filter_config(MCAN_Type *ptr, mcan_global_filter_config_t *filter_config);

/**
 * @brief Set CAN filter element
 * @param [in] ptr MCAN base
 * @param [in] filter_elem CAN filter element
 * @param [in] index CAN Filter element index
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_set_filter_element(MCAN_Type *ptr, const mcan_filter_elem_t *filter_elem, uint32_t index);

/**
 * @brief Write Frame to CAN TX Buffer
 * @param [in] ptr MCAN base
 * @param [in] index TX Buffer Index
 * @param [in] tx_frame TX frame
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_write_txbuf(MCAN_Type *ptr, uint32_t index, mcan_tx_frame_t *tx_frame);

/**
 * @brief Write Frame CAN to TXFIFO
 * @param [in] ptr MCAN base
 * @param [in] tx_frame TX frame
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_write_txfifo(MCAN_Type *ptr, mcan_tx_frame_t *tx_frame);

/**
 * @brief Read message from CAN RXBUF
 * @param [in] ptr MCAN base
 * @param [in] index Index of RXBUF
 * @param [out] rx_frame Buffer to hold RX frame
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_read_rxbuf(MCAN_Type *ptr, uint32_t index, mcan_rx_message_t *rx_frame);

/**
 * @brief Read message from CAN RXBUF
 * @param [in] ptr MCAN base
 * @param [in] fifo_index RXFIFO index, 0 - RXFO0, 1 - RXFIFO1
 * @param [out] rx_frame Buffer to hold RX frame
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_read_rxfifo(MCAN_Type *ptr, uint32_t fifo_index, mcan_rx_message_t *rx_frame);

/**
 * @brief Read TX Event from CAN TX EVENT FIFO
 * @param [in] ptr MCAN base
 * @param [out] tx_evt TX Event Buffer
 * @retval status_success if no errors happened
 * @retval status_mcan_tx_evt_fifo_empty if there are no TX events available
 * @retval status_invalid_argument if any parameters are invalid
 */
hpm_stat_t mcan_read_tx_evt_fifo(MCAN_Type *ptr, mcan_tx_event_fifo_elem_t *tx_evt);

/**
 * @brief Transmit CAN message in blocking way
 * @param [in] ptr MCAN base
 * @param [in] tx_frame CAN Transmit Message buffer
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_transmit_blocking(MCAN_Type *ptr, mcan_tx_frame_t *tx_frame);

/**
 * @brief Request TXFIFO and fill data into TXFIFO
 * @note This API can be used to prepare the data for several CAN frames prior to transmission.
 *       After this operation, software can call `mcan_send_add_request(ptr, *fifo_index)` API to trigger a transmission
 *       or call `mcan_send_add_requests(ptr, fifo_index_masks)` to trigger several transmissions
 * @param [in] ptr MCAN base
 * @param [in] tx_frame CAN Transmit Message buffer
 * @param [out] fifo_index The index of the element in FIFO assigned to the tx_frame
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_request_and_fill_txfifo(MCAN_Type *ptr, mcan_tx_frame_t *tx_frame, uint32_t *fifo_index);

/**
 * @brief Transmit CAN message via TX FIFO in non-blocking way
 * @param [in] ptr MCAN base
 * @param [in] tx_frame CAN Transmit Message buffer
 * @param [out] fifo_index The index of the element in FIFO assigned to the tx_frame
 *
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_transmit_via_txfifo_nonblocking(MCAN_Type *ptr, mcan_tx_frame_t *tx_frame, uint32_t *fifo_index);

/**
 * @brief Transmit CAN message via TX in non-blocking way
 * @param [in] ptr MCAN base
 * @param [in] index Index of TX Buffer
 * @param [in] tx_frame CAN Transmit Message buffer
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_transmit_via_txbuf_nonblocking(MCAN_Type *ptr, uint32_t index, mcan_tx_frame_t *tx_frame);

/**
 * @brief Receive CAN Frame from RXBUF in blocking way
 * @param [in] ptr MCAN base
 * @param [in] index RXBUF index
 * @param [out] rx_frame Buffer to hold Received Frame
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_receive_from_buf_blocking(MCAN_Type *ptr, uint32_t index, mcan_rx_message_t *rx_frame);

/**
 * @brief Receive CAN Frame from RXFIFO in blocking way
 * @param [in] ptr MCAN base
 * @param [in] fifo_index RXFIFO index, 0 - RXFIFO0, 1 - RXFIFO1
 * @param [out] rx_frame Buffer to hold Received Frame
 * @return status_success if no errors reported
 */
hpm_stat_t mcan_receive_from_fifo_blocking(MCAN_Type *ptr, uint32_t fifo_index, mcan_rx_message_t *rx_frame);

/**
 * @brief Get Timestamp from MCAN TX Event
 * @param [in] ptr MCAN base
 * @param [in] tx_evt TX Event Element
 * @param [out] timestamp Timestamp value
 * @retval status_success if no errors happened
 * @retval status_invalid_argument if any parameters are invalid
 * @retval status_mcan_timestamp_not_exist if no timestamp information is available
 */
hpm_stat_t mcan_get_timestamp_from_tx_event(MCAN_Type *ptr,
                                            const mcan_tx_event_fifo_elem_t *tx_evt,
                                            mcan_timestamp_value_t *timestamp);

/**
 * @brief Get Timestamp from MCAN RX frame
 * @param [in] ptr MCAN base
 * @param [in] rx_msg Received message
 * @param [out] timestamp Timestamp value
 * @retval status_success if no errors happened
 * @retval status_invalid_argument if any parameters are invalid
 * @retval status_mcan_timestamp_not_exist if no timestamp information is available
 */
hpm_stat_t mcan_get_timestamp_from_received_message(MCAN_Type *ptr,
                                                    const mcan_rx_message_t *rx_msg,
                                                    mcan_timestamp_value_t *timestamp);

/**
 * @brief Parse the Protocol Status register value
 * @param [in] psr Protocol Status Register Value
 * @param [out] protocol_status Translated Protocol Status
 *
 * @retval status_invalid_argument if any parameters are invalid
 * @retval status_success if no errors happened
 */
hpm_stat_t mcan_parse_protocol_status(uint32_t psr, mcan_protocol_status_t *protocol_status);

/**
 * @brief Get MCAN Protocol Status
 * @param [in] ptr MCAN base
 * @param [out] protocol_status Translated Protocol status
 *
 * @retval status_invalid_argument if any parameters are invalid
 * @retval status_success if no errors happened
 */
hpm_stat_t mcan_get_protocol_status(MCAN_Type *ptr, mcan_protocol_status_t *protocol_status);

/**
 * @}
 *
 */

#ifdef __cplusplus
}
#endif


#endif /* HPM_MCAN_DRV_H */
