/**
 * CAN1 Generated Driver Source File
 * 
 * @file      can1.c
 *            
 * @ingroup   candriver
 *            
 * @brief     This is the generated driver source file for CAN1 driver
 *
 * @skipline @version   PLIB Version 1.0.5
 *            
 * @skipline  Device : dsPIC33AK512MPS512
*/

/*
? [2026] Microchip Technology Inc. and its subsidiaries.

    Subject to your compliance with these terms, you may use Microchip 
    software and any derivatives exclusively with Microchip products. 
    You are responsible for complying with 3rd party license terms  
    applicable to your use of 3rd party software (including open source  
    software) that may accompany Microchip software. SOFTWARE IS ?AS IS.? 
    NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS 
    SOFTWARE, INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT,  
    MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 
    WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, 
    INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY 
    KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF 
    MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE 
    FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP?S 
    TOTAL LIABILITY ON ALL CLAIMS RELATED TO THE SOFTWARE WILL NOT 
    EXCEED AMOUNT OF FEES, IF ANY, YOU PAID DIRECTLY TO MICROCHIP FOR 
    THIS SOFTWARE.
*/

// Section: Included Files

#include <string.h>
#include "../can_types.h"    
#include "../can1.h"

// CAN Bus FIFO Memory information
#define CAN1_FIFO_ALLOCATE_RAM_SIZE    64UL // CAN FIFO allocated ram size based on (number of FIFO x FIFO message Payload size x Message object DLC size)

// CAN Bus Transmit FIFO Memory information
#define CAN1_TX_MSG_SEND_REQ_BIT_POS   0x200UL // CAN FIFO TX Message Send Request bit 
#define CAN1_TX_INC_FIFO_PTR_BIT_POS   0x100UL // CAN FIFO Increment Head/Tail bit
#define CAN_TX_FIFO_WORD_0      0
#define CAN_TX_FIFO_WORD_1      1
#define CAN_TX_FIFO_WORD_2      2

// CAN Message object arbitration field information
#define CAN_MSG_OBJ_DLC_FIELD_SIZE          0xFU
#define CAN_MSG_OBJ_ID_TYPE_MASK       0x10U
#define CAN_MSG_OBJ_ID_TYPE_POS       0x4U
#define CAN_MSG_OBJ_RTR_POS           0x5U
#define CAN_MSG_OBJ_RTR_MASK           0x20U
#define CAN_MSG_OBJ_FRAME_TYPE_MASK    0x20U
#define CAN_MSG_OBJ_FRAME_TYPE_POS    0x5U
#define CAN_MSG_OBJ_BRS_MASK           0x40U
#define CAN_MSG_OBJ_BRS_POS           0x6U
#define CAN_MSG_OBJ_FORMAT_TYPE_MASK   0x80U
#define CAN_MSG_OBJ_FORMAT_TYPE_POS   0x7U
#define CAN_STD_MSG_ID_MAX_SIZE             0x7FFU
#define CAN_MSG_OBJ_SID_POS           0x12U
#define CAN_EXT_MSG_ID_MAX_SIZE        0x3FFFFU
#define CAN_MSG_OBJ_EID_POS       0xBU

//The time required for can bus to wake up from bus off and integrate is 128 times the recessive bits,
//Considering the highest clock speed of CAN 80MHz the minimun TBC required in 0xDC000, providing the time double of 0xDC000 is 1B8000
#define CAN_MODE_SET_TIMEOUT 0x1B8000U

// Section: Driver Interface
const struct CAN_INTERFACE CAN1 = {
    .Initialize = CAN1_Initialize,
    .Deinitialize = CAN1_Deinitialize,
    .OperationModeSet = CAN1_OperationModeSet,
    .OperationModeGet = CAN1_OperationModeGet,
    .IsBusOff = CAN1_IsBusOff,
    .SleepMode = CAN1_Sleep,
    .Transmit = CAN1_Transmit,
    .TransmitFIFOStatusGet = CAN1_TransmitFIFOStatusGet,
    .IsTxErrorActive = CAN1_IsTxErrorActive,
    .IsTxErrorPassive = CAN1_IsTxErrorPassive,
    .IsTxErrorWarning = CAN1_IsTxErrorWarning,
    .Receive = NULL,
    .ReceiveMessageGet = NULL,
    .IsRxErrorPassive = NULL,
    .IsRxErrorWarning = NULL,
    .IsRxErrorActive = NULL,
    .ReceivedMessageCountGet = NULL,
    .InvalidMessageCallbackRegister = &CAN1_InvalidMessageCallbackRegister,
    .BusWakeUpActivityCallbackRegister = &CAN1_BusWakeUpActivityCallbackRegister,
    .BusErrorCallbackRegister = &CAN1_BusErrorCallbackRegister,
    .ModeChangeCallbackRegister = &CAN1_ModeChangeCallbackRegister,
    .SystemErrorCallbackRegister = &CAN1_SystemErrorCallbackRegister,
    .TxAttemptCallbackRegister = &CAN1_TxAttemptCallbackRegister,
    .RxBufferOverFlowCallbackRegister = NULL,
    .Tasks = CAN1_Tasks
};

// Section: Private Variable Definitions
// Start CAN Message Memory Base Address
static uint8_t __attribute__((aligned(4)))can1FifoMsg[CAN1_FIFO_ALLOCATE_RAM_SIZE];

// CAN Default Callback Handler
static void (*CAN1_InvalidMessageHandler)(void) = NULL;
static void (*CAN1_BusWakeUpActivityHandler)(void) = NULL;
static void (*CAN1_BusErrorHandler)(void) = NULL;
static void (*CAN1_ModeChangeHandler)(void) = NULL;
static void (*CAN1_SystemErrorHandler)(void) = NULL;
static void (*CAN1_TxAttemptHandler)(void) = NULL;

/**
 @ingroup  candriver
 @struct   CAN1 FIFO parameters information data structure
 @brief    This Data structure is to implement a CAN FIFO parameters information
*/
struct CAN1_FIFO_INFO
{
    uint8_t payloadSize;
    uint8_t msgDeepSize;
    uint32_t *address;
};

// Section: Private Function Definitions

/**
 @ingroup  candriver
 @static   Get the DLC enum based decimal value
 @brief    This function get the DLC enum based decimal value
*/
static uint8_t CAN1_DlcToDataBytesGet(const enum CAN_DLC dlc)
{
    static const uint8_t dlcByteSize[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U};
    return dlcByteSize[dlc];
}

/**
 @ingroup  candriver
 @static   Get the FIFO user address, message depth and payload size information
 @brief    This function get the FIFO user address, message depth and payload size
           information.
*/

static void CAN1_FIFO_InfoGet(const uint8_t fifoNum, volatile struct CAN1_FIFO_INFO *fifoInfo)
{   
    switch (fifoNum) 
    {
        case CAN1_TXQ:
            fifoInfo->address = (uint32_t *) &C1TXQUA;
            fifoInfo->payloadSize = 8U;
            fifoInfo->msgDeepSize = 4U;
            break;
     
        default:
            fifoInfo->address = NULL;
            fifoInfo->payloadSize = 0U;
            fifoInfo->msgDeepSize = 0U;
            break;
    }
}

/**
 @ingroup  candriver
 @static   Enable the transmit FIFO message send request bit
 @brief    This function enables The FIFO transmit message send request bit
*/
static void CAN1_TX_FIFO_MessageSendRequest(const enum CAN1_TX_FIFO_CHANNELS fifoChannel)
{   
    switch (fifoChannel) 
    {           
        case CAN1_TXQ:
            // Update the CAN1_TXQ message pointer; Set TXREQ bit
            C1TXQCON = (C1TXQCON | (CAN1_TX_MSG_SEND_REQ_BIT_POS | CAN1_TX_INC_FIFO_PTR_BIT_POS));
            break;

        default:
            break;
    }      
}

/**
 @ingroup  candriver
 @static   Read the message object from user input and update to the CAN1 TX FIFO
 @brief    This function Read the message object from user input and update
           to the CAN1 TX FIFO.
*/
static void CAN1_MessageWriteToFifo(uint32_t *txFifoObj, struct CAN_MSG_OBJ *txCanMsg)
{
    /*
    Transmit FIFO Object format:
    Transmit FIFO WORD_0:   |31:24|| SID<11>           | EID<17:13>             ||
                            |23:16|| EID<12:5>                                  ||
                            |15: 8|| EID<4:0>          | SID<10:8>              ||
                            | 7: 0||           SID<7:0>                         ||
                             
    
    Transmit FIFO WORD_1:   |31:24||Sequence<22:15>(Not implemented)            ||
                            |23:16||Sequence<14:7>(Not implemented)             ||
                            |15: 8||Sequence<6:0>(Not implemented) |  ESI<1>    ||
                            | 7: 0||FDF<1> | BRS<1> | RTR<1> | IDE<1> | DLC<3:0>||
                                 
                          
    Transmit FIFO WORD_2 to |31:24|| Transmit Data Byte 3,7,11.. n              ||
    Transmit FIFO WORD_n:   |23:16|| Transmit Data Byte 2,6,10.. n-1            ||
                            |15: 8|| Transmit Data Byte 1,5,9.. n-2             ||
                            | 7: 0|| Transmit Data Byte 0,4,8.. n-3             ||
    */
    
    uint8_t dlcByteSize;

    /* message is standard identifier */
    if(txCanMsg->field.idType == (uint8_t) CAN_FRAME_STD) 
    {
        // SID <10:0>
        txFifoObj[CAN_TX_FIFO_WORD_0] = (txCanMsg->msgId & CAN_STD_MSG_ID_MAX_SIZE);
    } 
    else 
    {
        /* message is extended identifier */
        // SID <10:0> and EID <17:0>
        txFifoObj[CAN_TX_FIFO_WORD_0] = (((txCanMsg->msgId >> CAN_MSG_OBJ_SID_POS) & CAN_STD_MSG_ID_MAX_SIZE) | 
                        (txCanMsg->msgId & CAN_EXT_MSG_ID_MAX_SIZE) << CAN_MSG_OBJ_EID_POS);
    }

    // DLC <3:0>, IDE <1>, RTR <1>, BRS <1>, FDF <1> 
    txFifoObj[CAN_TX_FIFO_WORD_1] = (txCanMsg->field.dlc & CAN_MSG_OBJ_DLC_FIELD_SIZE) | 
                    ((txCanMsg->field.idType << CAN_MSG_OBJ_ID_TYPE_POS) & CAN_MSG_OBJ_ID_TYPE_MASK) | 
                    ((txCanMsg->field.frameType << CAN_MSG_OBJ_FRAME_TYPE_POS) & CAN_MSG_OBJ_FRAME_TYPE_MASK) | 
                    ((txCanMsg->field.brs << CAN_MSG_OBJ_BRS_POS) & CAN_MSG_OBJ_BRS_MASK) | 
                    ((txCanMsg->field.formatType << CAN_MSG_OBJ_FORMAT_TYPE_POS) & CAN_MSG_OBJ_FORMAT_TYPE_MASK);
        
    // Data frame message
    if(txCanMsg->field.frameType == (uint8_t) CAN_FRAME_DATA)
    {
        dlcByteSize = CAN1_DlcToDataBytesGet(txCanMsg->field.dlc);

        // Coping TX message object to FIFO
        (void)memcpy((uint8_t*)(&txFifoObj[CAN_TX_FIFO_WORD_2]), txCanMsg->data, dlcByteSize);
    } 
    // RTR frame message
    else
    {
        txFifoObj[CAN_TX_FIFO_WORD_1] = txFifoObj[CAN_TX_FIFO_WORD_1] | (((bool) 1 << CAN_MSG_OBJ_RTR_POS) & CAN_MSG_OBJ_RTR_MASK);
    }
}

/**
 @ingroup  candriver
 @static   Configure the CAN1 transmit FIFO settings
 @brief    This function configure the CAN1 transmit FIFO settings
*/
static void CAN1_TX_FIFO_Configuration(void)
{
    // TXQNIE ; TXQEIE ; TXATIE ; UINC ; TXREQ ; FRESET ; TXPRI 0; TXAT Unlimited attempts; FSIZE 4; PLSIZE 8; 
    C1TXQCON = 0x3400480UL;
}

/**
 @ingroup  candriver
 @static   Configure the CAN1 bit rate settings
 @brief    This function configure the CAN1 bit rate settings
*/
static void CAN1_BitRateConfiguration(void)
{
    // SJW 9; TSEG2 9; TSEG1 28; BRP 0; 
    C1NBTCFG = 0x1C0909UL;
}

/**
 @ingroup  candriver
 @static   Enable the CAN1 Error Notification interrupt
 @brief    This function enables the CAN1  error notification  interrupt
*/
static void CAN1_ErrorNotificationEnable(void)
{
    // CAN1 CAN1 Callback initialize
    CAN1_InvalidMessageCallbackRegister(&CAN1_InvalidMessageCallback);
    CAN1_BusWakeUpActivityCallbackRegister(&CAN1_BusWakeUpActivityCallback);
    CAN1_BusErrorCallbackRegister(&CAN1_BusErrorCallback);
    CAN1_ModeChangeCallbackRegister(&CAN1_ModeChangeCallback);
    CAN1_SystemErrorCallbackRegister(&CAN1_SystemErrorCallback);
    CAN1_TxAttemptCallbackRegister(&CAN1_TxAttemptCallback);
}

// Section: Driver Interface Function Definitions
void CAN1_Initialize(void)
{  
    // DNCNT ; ISOCRCEN enabled; PXEDIS ; WAKFIL ; WFT ; BRSDIS enabled; SIDL ; ON enabled; RTXAT ; ESIGM ; SERR2LOM ; STEF disabled; TXQEN enabled; REQOP Configuration mode; ABAT ; TXBWS ; 
    C1CON = 0x4909760UL;  

    /* Place CAN1 module in configuration mode */
    if(CAN_OP_MODE_REQUEST_SUCCESS == CAN1_OperationModeSet(CAN_CONFIGURATION_MODE))
    {
        /* Initialize the C1FIFOBA with the start address of the CAN1 FIFO message object area. */
        /* cppcheck-suppress misra-c2012-11.4
        * Assigning an array pointer to CAN FIFO Address register
        */
        C1FIFOBA = (uint32_t) &can1FifoMsg[0];
        
        // DNCNT ; ISOCRCEN enabled; PXEDIS ; WAKFIL ; WFT ; BRSDIS enabled; SIDL ; ON enabled; RTXAT ; ESIGM ; SERR2LOM ; STEF disabled; TXQEN enabled; REQOP Configuration mode; ABAT ; TXBWS ; 
        C1CON = 0x4909760UL;
    
        // Disabled CAN1 Store in Transmit Event FIFO bit
        C1CONbits.STEF = 0;
        // Enabled CAN1 Transmit Queue bit
        C1CONbits.TXQEN = 1;
        
        /* configure CAN1 Bit rate settings */
        CAN1_BitRateConfiguration();        
        
        /* configure CAN1 FIFO settings */
        CAN1_TX_FIFO_Configuration();

        /* CAN Error Notification */
        CAN1_ErrorNotificationEnable();
        
        /* Place CAN1 module in Normal Operation mode */
        (void)CAN1_OperationModeSet(CAN_NORMAL_2_0_MODE);
    }
}

void CAN1_Deinitialize(void)
{
    /* Place CAN1 module in configuration mode */
    if(CAN_OP_MODE_REQUEST_SUCCESS == CAN1_OperationModeSet(CAN_CONFIGURATION_MODE))
    {        
        C1CON = 0x4980760UL;  
           
        /* Reset bit rate settings to POR*/
        C1NBTCFG = 0x3E0F0FU;
        
        /* configure CAN1 FIFO settings */
        /* Reset TX FIFO settings to POR*/
        C1TXQCON = 0x600480U;

    }
    
    /* Disable the CAN1 module */
    C1CONbits.ON = 0U;
}

enum CAN_OP_MODE_STATUS CAN1_OperationModeSet(const enum CAN_OP_MODES requestMode) 
{
    enum CAN_OP_MODE_STATUS status = CAN_OP_MODE_REQUEST_SUCCESS;
    
    if((CAN_CONFIGURATION_MODE == CAN1_OperationModeGet()) || (requestMode == CAN_DISABLE_MODE)
            || (requestMode == CAN_CONFIGURATION_MODE))
    {
        C1CONbits.REQOP = requestMode;
        C1TSCONbits.TBCEN = 1U;
        while(C1CONbits.OPMOD != requestMode) 
        {
            // This condition is avoiding the system error case endless loop
            if(C1INTbits.SERRIF == 1)
            {
                status = CAN_OP_MODE_SYS_ERROR_OCCURED;
                break;
            }
            else if(C1TBC > CAN_MODE_SET_TIMEOUT)
            {
                status = CAN_OP_MODE_REQUEST_FAIL;
                break;
            }
        }
        C1TSCONbits.TBCEN = 0U;
    }
    else
    {
        status = CAN_OP_MODE_REQUEST_FAIL;
    }
    
    return status;
}

enum CAN_OP_MODES CAN1_OperationModeGet(void) 
{
    return C1CONbits.OPMOD;
}

enum CAN_TX_MSG_REQUEST_STATUS CAN1_Transmit(const enum CAN1_TX_FIFO_CHANNELS fifoChannel, struct CAN_MSG_OBJ *txCanMsg)
{
    volatile struct CAN1_FIFO_INFO fifoInfo;
    CAN1_FIFO_InfoGet(fifoChannel, &fifoInfo);
    enum CAN_TX_MSG_REQUEST_STATUS txMsgStatus = CAN_TX_MSG_REQUEST_SUCCESS;
    
    // If CAN module is configured in Non-BRS mode and TX message object has BRS set
    if((txCanMsg->field.brs == (bool) 1) && (C1CONbits.BRSDIS == (bool) 1))
    {
        txMsgStatus |= CAN_TX_MSG_REQUEST_BRS_ERROR;
    }
    
    // If CAN 2.0 mode, Tx Message object has more than 8 bytes of DLC Size
    // CAN 2.0 mode DLC supports upto 8 byte 
    if(txCanMsg->field.dlc > (uint8_t) DLC_8) 
    {
       txMsgStatus |= CAN_TX_MSG_REQUEST_DLC_EXCEED_ERROR;
    }
    
    // If any CAN TX message object has DLC size more than CAN TX FIFO Payload size
    if(CAN1_DlcToDataBytesGet(txCanMsg->field.dlc) > fifoInfo.payloadSize) 
    {
        txMsgStatus |= CAN_TX_MSG_REQUEST_DLC_EXCEED_ERROR;
    }
    
    if(CAN_TX_MSG_REQUEST_SUCCESS == txMsgStatus)
    {
        if(CAN_TX_FIFO_AVAILABLE == CAN1_TransmitFIFOStatusGet(fifoChannel))
        {
            if((uint32_t *)(*(fifoInfo.address)) != NULL) 
            {
                /* cppcheck-suppress misra-c2012-11.4
                * Parsing CAN Message object location address
                */
                CAN1_MessageWriteToFifo((uint32_t *) *fifoInfo.address, txCanMsg);
                CAN1_TX_FIFO_MessageSendRequest(fifoChannel);
            }         
        }
        else
        {
            txMsgStatus |= CAN_TX_MSG_REQUEST_FIFO_FULL;
        }
    }

    return txMsgStatus;
}

enum CAN_TX_FIFO_STATUS CAN1_TransmitFIFOStatusGet(const enum CAN1_TX_FIFO_CHANNELS fifoChannel)
{
    enum CAN_TX_FIFO_STATUS fifoStatus;
    
    switch (fifoChannel) 
    {
        case CAN1_TXQ:
            fifoStatus = ((C1TXQSTA & 0x1) ? CAN_TX_FIFO_AVAILABLE:CAN_TX_FIFO_FULL);
            break;
            
        default:
            fifoStatus = CAN_TX_FIFO_FULL;
            break;
    }
    
    return fifoStatus;
}

bool CAN1_IsBusOff(void)
{
    return C1TRECbits.TXBO;
}

bool CAN1_IsTxErrorPassive(void) 
{
    return C1TRECbits.TXBP;
}

bool CAN1_IsTxErrorWarning(void) 
{
    return C1TRECbits.TXWARN;
}

bool CAN1_IsTxErrorActive(void)
{
    bool errorState = false;
    if((0 < C1TRECbits.TERRCNT) && (C1TRECbits.TERRCNT < 128)) 
    {
        errorState = true;
    }
    
    return errorState;
}

void CAN1_Sleep(void)
{
    C1INTbits.WAKIF = 0;
    C1INTbits.WAKIE = 1;
    
    // CAN Info Interrupt Enable bit
    IEC1bits.C1IE = 1;  
    
    /* put the module in disable mode */
   (void)CAN1_OperationModeSet(CAN_DISABLE_MODE);
}

void CAN1_InvalidMessageCallbackRegister(void (*handler)(void))
{
    if(NULL != handler)
    {
        CAN1_InvalidMessageHandler = handler;
    }
}

void __attribute__ ((weak)) CAN1_InvalidMessageCallback ( void )
{ 

} 

void CAN1_BusWakeUpActivityCallbackRegister(void (*handler)(void))
{
    if(NULL != handler)
    {
        CAN1_BusWakeUpActivityHandler = handler;
    }
}

void __attribute__ ((weak)) CAN1_BusWakeUpActivityCallback ( void )
{ 

} 

void CAN1_BusErrorCallbackRegister(void (*handler)(void))
{
    if(NULL != handler)
    {
        CAN1_BusErrorHandler = handler;
    }
}

void __attribute__ ((weak)) CAN1_BusErrorCallback ( void )
{ 

} 

void CAN1_ModeChangeCallbackRegister(void (*handler)(void))
{
    if(NULL != handler)
    {
        CAN1_ModeChangeHandler = handler;
    }
}

void __attribute__ ((weak)) CAN1_ModeChangeCallback ( void )
{ 

} 

void CAN1_SystemErrorCallbackRegister(void (*handler)(void))
{
    if(NULL != handler)
    {
        CAN1_SystemErrorHandler = handler;
    }
}

void __attribute__ ((weak)) CAN1_SystemErrorCallback ( void )
{ 

} 

void CAN1_TxAttemptCallbackRegister(void (*handler)(void))
{
    if(NULL != handler)
    {
        CAN1_TxAttemptHandler = handler;
    }
}

void __attribute__ ((weak)) CAN1_TxAttemptCallback(void)
{ 

}

/* cppcheck-suppress misra-c2012-8.4
*
* (Rule 8.4) REQUIRED: A compatible declaration shall be visible when an object or 
* function with external linkage is defined
*
* Reasoning: Interrupt declaration are provided by compiler and are available
* outside the driver folder
*/
void __attribute__ ( ( __interrupt__ ) ) _C1Interrupt(void)
{
    // Bus Wake-up Activity Interrupt 
    if(1 == C1INTbits.WAKIF)
    {
        if(CAN1_BusWakeUpActivityHandler != NULL)
        {
            CAN1_BusWakeUpActivityHandler();
        }
        
        C1INTbits.WAKIF = 0;
    }
    
    IFS1bits.C1IF = 0;
}

void CAN1_Tasks(void)
{
    if(1 == C1INTbits.IVMIF)
    {
        if(CAN1_InvalidMessageHandler != NULL)
        {
            CAN1_InvalidMessageHandler();
        }
       
        C1INTbits.IVMIF = 0;
    }
    
    if(1 == C1INTbits.CERRIF)
    {
        if(CAN1_BusErrorHandler != NULL)
        {
            CAN1_BusErrorHandler();
        }
       
        C1INTbits.CERRIF = 0;
    }
    
    if(1 == C1INTbits.MODIF)
    {
        if(CAN1_ModeChangeHandler != NULL)
        {
            CAN1_ModeChangeHandler();
        }
       
        C1INTbits.MODIF = 0;
    }
    
    if(1 == C1INTbits.SERRIF)
    {
        if(CAN1_SystemErrorHandler != NULL)
        {
            CAN1_SystemErrorHandler();
        }
       
        C1INTbits.SERRIF = 0;
    }
    
    if(1 == C1INTbits.TXATIF)
    {
        if(CAN1_TxAttemptHandler != NULL)
        {
            CAN1_TxAttemptHandler();
        }
    }
    
}

/**
 End of File
*/


