/**
  ECAN Generated Driver  File

  @Company
    Microchip Technology Inc.

  @File Name
    ecan.c

  @Summary
    This is the generated driver implementation for the CAN driver using PIC10 / PIC12 / PIC16 / PIC18 MCUs

  @Description
    This source file provides APIs for CAN.
    Generation Information :
        Product Revision  :  PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.81.8
        Device            :  PIC18F25K83
        Driver Version    :  3.0.0
    The generated drivers are tested against the following:
        Compiler          :  XC8 2.36 and above
        MPLAB 	          :  MPLAB X 6.00
*/

/*
    (c) 2018 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. It is your responsibility to comply with third party 
    license terms applicable to your use of third party software (including open source software) that 
    may accompany Microchip software.
    
    THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER 
    EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY 
    IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND 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 IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT 
    OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS 
    SOFTWARE.
*/

/**
  Section: Included Files
*/

#include <xc.h>
#include "ecan.h"

static void (*RXBnInterruptHandler)(void);
static void (*RXBnOverflowHandler)(void);
static void (*BusOffHandler)(void);
static void (*TXPassiveHandler)(void);
static void (*RXPassiveHandler)(void);
static void (*TXWarningHandler)(void);
static void (*RXWarningHandler)(void);

/**
    Local Functions
*/
static uint32_t convertReg2ExtendedCANid(uint8_t tempRXBn_EIDH, uint8_t tempRXBn_EIDL, uint8_t tempRXBn_SIDH, uint8_t tempRXBn_SIDL);
static uint32_t convertReg2StandardCANid(uint8_t tempRXBn_SIDH, uint8_t tempRXBn_SIDL);
static void convertCANid2Reg(uint32_t tempPassedInID, uint8_t canIdType, uint8_t *passedInEIDH, uint8_t *passedInEIDL, uint8_t *passedInSIDH, uint8_t *passedInSIDL);

static void RXBnDefaultInterruptHandler(void) {}
static void RXBnOverflowDefaultHandler(void) {}
static void BusOffDefaultHandler(void) {}
static void TXPassiveDefaultHandler(void) {}
static void RXPassiveDefaultHandler(void) {}
static void TXWarningDefaultHandler(void) {}
static void RXWarningDefaultHandler(void) {}

void ECAN_Initialize(void)
{
    CANCON = 0x80;
    while (0x80 != (CANSTAT & 0xE0)); // wait until ECAN is in config mode

    /**
    Mode 2
    */
    ECANCON = 0x90;

    /**
    Initialize CAN I/O
    */
    CIOCON = 0x00;
    
    /**
    Mask and Filter definitions
    ........................................................    
    CAN ID		ID Type		Mask				Filter		Buffer    
    ........................................................    
    0x123		SID		Acceptance Mask 0		Filter 0	FIFO
    ........................................................
    */
    
    /**
    Configure Generic Buffers to be Transmit or Receive
    */
    BSEL0 = 0x00;
  /**
    Mask and Filter definitions
    ........................................................    
    CAN ID		ID Type		Mask				Filter		Buffer    
    ........................................................    
    ........................................................
    */
    
    /*
     * Mask 0 is 11 bits for filters 0 and 1 only
     * filter set for 3 recipient bits
     * Mask 1 is copy of mask 0 but for other filters
     */
    convertCANid2Reg(0x070, dSTANDARD_CAN_MSG_ID_2_0B, &RXM0EIDH, &RXM0EIDL, &RXM0SIDH, &RXM0SIDL);
    convertCANid2Reg(0x070, dSTANDARD_CAN_MSG_ID_2_0B, &RXM1EIDH, &RXM1EIDL, &RXM1SIDH, &RXM1SIDL);

    // filter 0 is broadcast message
    convertCANid2Reg(0x000, dSTANDARD_CAN_MSG_ID_2_0B, &RXF0EIDH, &RXF0EIDL, &RXF0SIDH, &RXF0SIDL);  
    
    // filter 1 is message for controller
    convertCANid2Reg(0x010, dSTANDARD_CAN_MSG_ID_2_0B, &RXF1EIDH, &RXF1EIDL, &RXF1SIDH, &RXF1SIDL);  
   
    // filter 2 is message for recipient n�7, not yet defined
    convertCANid2Reg(0x070, dSTANDARD_CAN_MSG_ID_2_0B, &RXF2EIDH, &RXF2EIDL, &RXF2SIDH, &RXF2SIDL);  

    /*
     * ENABLE FILTERS
     * 
     * RXF7EN RXF6EN RXF5EN RXF4EN RXF3EN RXF2EN RXF1EN RXF0EN
     * 0b 00000111
     */
    RXFCON0 = 0x07;
    
    
    /*
     * Assign Filters to Masks
     * 
     * Filter 0 set on mask 0
     * Filter 1 set on mask 0
     * Filter 2 set on mask 1
     * 0b F3 F2 F1 F0
     * 0b 00 01 00 00
     */
    MSEL0 = 0x10;

    /**
    Initialize CAN Timings
    */
    
   /**
	Baud rate: 250kbps
	System frequency: 64000000
    ECAN clock frequency: 64000000
	Time quanta: 8
	Sample point: 1-1-4-2
	Sample point: 75%
	*/
    
    BRGCON1 = 0x0F;
    BRGCON2 = 0x98;
    BRGCON3 = 0x81;

    
    ECAN_SetRXBnInterruptHandler(RXBnDefaultInterruptHandler);
    PIR5bits.RXBnIF = 0;
    PIE5bits.RXBnIE = 1;
    
    ECAN_SetRXBnOverflowHandler(RXBnOverflowDefaultHandler);
    ECAN_SetBusOffHandler(BusOffDefaultHandler);
    ECAN_SetTXPassiveHandler(TXPassiveDefaultHandler);
    ECAN_SetRXPassiveHandler(RXPassiveDefaultHandler);
    ECAN_SetTXWarningHandler(TXWarningDefaultHandler);
    ECAN_SetRXWarningHandler(RXWarningDefaultHandler);
    PIR5bits.ERRIF = 0;
    PIE5bits.ERRIE = 1;
    
    CANCON = 0x00;
    while (0x00 != (CANSTAT & 0xE0)); // wait until ECAN is in Normal mode

}
 /**
  Section: ECAN APIs
*/
void CAN_sleep(void) 
{
    CANCON = 0x20; // request disable mode
    while ((CANSTAT & 0xE0) != 0x20); // wait until ECAN is in disable mode   
    //Wake up from sleep should set the CAN module straight into Normal mode
}

uint8_t CAN_transmit(uCAN_MSG *tempCanMsg) 
{
    uint8_t tempEIDH = 0;
    uint8_t tempEIDL = 0;
    uint8_t tempSIDH = 0;
    uint8_t tempSIDL = 0;
    uint8_t returnValue = 0;

    if (TXB0CONbits.TXREQ != 1) 
    {
        convertCANid2Reg(tempCanMsg->frame.id, tempCanMsg->frame.idType, &tempEIDH, &tempEIDL, &tempSIDH, &tempSIDL);

        TXB0EIDH = tempEIDH;
        TXB0EIDL = tempEIDL;
        TXB0SIDH = tempSIDH;
        TXB0SIDL = tempSIDL;
        TXB0DLC  = tempCanMsg->frame.dlc | ((tempCanMsg->frame.rtr)<<6);
        TXB0D0   = tempCanMsg->frame.data0;
        TXB0D1   = tempCanMsg->frame.data1;
        TXB0D2   = tempCanMsg->frame.data2;
        TXB0D3   = tempCanMsg->frame.data3;
        TXB0D4   = tempCanMsg->frame.data4;
        TXB0D5   = tempCanMsg->frame.data5;
        TXB0D6   = tempCanMsg->frame.data6;
        TXB0D7   = tempCanMsg->frame.data7;

        TXB0CONbits.TXREQ = 1; //Set the buffer to transmit		
        returnValue = 1;
        
    } 
    else if (TXB1CONbits.TXREQ != 1) 
    {

        convertCANid2Reg(tempCanMsg->frame.id, tempCanMsg->frame.idType, &tempEIDH, &tempEIDL, &tempSIDH, &tempSIDL);

        TXB1EIDH = tempEIDH;
        TXB1EIDL = tempEIDL;
        TXB1SIDH = tempSIDH;
        TXB1SIDL = tempSIDL;
        TXB1DLC  = tempCanMsg->frame.dlc | ((tempCanMsg->frame.rtr)<<6);
        TXB1D0   = tempCanMsg->frame.data0;
        TXB1D1   = tempCanMsg->frame.data1;
        TXB1D2   = tempCanMsg->frame.data2;
        TXB1D3   = tempCanMsg->frame.data3;
        TXB1D4   = tempCanMsg->frame.data4;
        TXB1D5   = tempCanMsg->frame.data5;
        TXB1D6   = tempCanMsg->frame.data6;
        TXB1D7   = tempCanMsg->frame.data7;

        TXB1CONbits.TXREQ = 1; //Set the buffer to transmit		
        returnValue = 1;
    } 
    else if (TXB2CONbits.TXREQ != 1) 
    {

        convertCANid2Reg(tempCanMsg->frame.id, tempCanMsg->frame.idType, &tempEIDH, &tempEIDL, &tempSIDH, &tempSIDL);

        TXB2EIDH = tempEIDH;
        TXB2EIDL = tempEIDL;
        TXB2SIDH = tempSIDH;
        TXB2SIDL = tempSIDL;
        TXB2DLC  = tempCanMsg->frame.dlc | ((tempCanMsg->frame.rtr)<<6);
        TXB2D0   = tempCanMsg->frame.data0;
        TXB2D1   = tempCanMsg->frame.data1;
        TXB2D2   = tempCanMsg->frame.data2;
        TXB2D3   = tempCanMsg->frame.data3;
        TXB2D4   = tempCanMsg->frame.data4;
        TXB2D5   = tempCanMsg->frame.data5;
        TXB2D6   = tempCanMsg->frame.data6;
        TXB2D7   = tempCanMsg->frame.data7;

        TXB2CONbits.TXREQ = 1; //Set the buffer to transmit		
        returnValue = 1;
    }

    return (returnValue);
}


/**
Version A2 has a silicon errata
This code works for all revisions
*/
//Fix for Errata
#define dRXB0CON_FIFO_POINTER_VALUE 0
#define dRXB1CON_FIFO_POINTER_VALUE 1
#define dB0CON_FIFO_POINTER_VALUE 2
#define dB1CON_FIFO_POINTER_VALUE 3
#define dB2CON_FIFO_POINTER_VALUE 4
#define dB3CON_FIFO_POINTER_VALUE 5
#define dB4CON_FIFO_POINTER_VALUE 6
#define dB5CON_FIFO_POINTER_VALUE 7

uint8_t CAN_receive(uCAN_MSG *tempCanMsg) {
    uint8_t returnValue = 0;
    uint8_t tempECANCON;
    uint8_t tempReg;

    tempReg = (CANCON & 0x0F); //get the next RX buffer to read
    tempECANCON = ECANCON; //Backup
    ECANCON |= (tempReg + 0x10);

    //Per Errata need to use this method to read out BxCON register
    switch (tempReg)
    {
        case dRXB0CON_FIFO_POINTER_VALUE:
            if (RXB0CONbits.RXFUL != 0) // Check RXB0
            {
                if ((RXB0SIDL & 0x08) == 0x08) //If Extended Message
                {
                    //message is extended
                    tempCanMsg->frame.idType = (uint8_t) dEXTENDED_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2ExtendedCANid(RXB0EIDH, RXB0EIDL, RXB0SIDH, RXB0SIDL);
                }
                else
                {
                    //message is standard
                    tempCanMsg->frame.idType = (uint8_t) dSTANDARD_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2StandardCANid(RXB0SIDH, RXB0SIDL);
                }

                tempCanMsg->frame.dlc   = RXB0DLC & 0x0F;
                tempCanMsg->frame.rtr   = RXB0DLC >> 6;
                tempCanMsg->frame.data0 = RXB0D0;
                tempCanMsg->frame.data1 = RXB0D1;
                tempCanMsg->frame.data2 = RXB0D2;
                tempCanMsg->frame.data3 = RXB0D3;
                tempCanMsg->frame.data4 = RXB0D4;
                tempCanMsg->frame.data5 = RXB0D5;
                tempCanMsg->frame.data6 = RXB0D6;
                tempCanMsg->frame.data7 = RXB0D7;
                RXB0CONbits.RXFUL = 0;
                returnValue = 1;
            }
            break;
        case dRXB1CON_FIFO_POINTER_VALUE:
            if (RXB1CONbits.RXFUL != 0) // Check RXB1
            {
                if ((RXB0SIDL & 0x08) == 0x08) //If Extended Message
                {
                    //message is extended
                    tempCanMsg->frame.idType = (uint8_t) dEXTENDED_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2ExtendedCANid(RXB0EIDH, RXB0EIDL, RXB0SIDH, RXB0SIDL);
                } else {
                    //message is standard
                    tempCanMsg->frame.idType = (uint8_t) dSTANDARD_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2StandardCANid(RXB0SIDH, RXB0SIDL);
                }

                tempCanMsg->frame.dlc = RXB0DLC & 0x0F;
                tempCanMsg->frame.rtr   = RXB0DLC >> 6;
                tempCanMsg->frame.data0 = RXB0D0;
                tempCanMsg->frame.data1 = RXB0D1;
                tempCanMsg->frame.data2 = RXB0D2;
                tempCanMsg->frame.data3 = RXB0D3;
                tempCanMsg->frame.data4 = RXB0D4;
                tempCanMsg->frame.data5 = RXB0D5;
                tempCanMsg->frame.data6 = RXB0D6;
                tempCanMsg->frame.data7 = RXB0D7;
                RXB1CONbits.RXFUL = 0;
                returnValue = 1;
            }
            break;
        case dB0CON_FIFO_POINTER_VALUE:
            if (B0CONbits.RXFUL != 0) //Check B0
            {
                if ((RXB0SIDL & 0x08) == 0x08) //If Extended Message
                {
                    //message is extended
                    tempCanMsg->frame.idType = (uint8_t) dEXTENDED_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2ExtendedCANid(RXB0EIDH, RXB0EIDL, RXB0SIDH, RXB0SIDL);
                } else {
                    //message is standard
                    tempCanMsg->frame.idType = (uint8_t) dSTANDARD_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2StandardCANid(RXB0SIDH, RXB0SIDL);
                }

                tempCanMsg->frame.dlc   = RXB0DLC & 0x0F;
                tempCanMsg->frame.rtr   = RXB0DLC >> 6;
                tempCanMsg->frame.data0 = RXB0D0;
                tempCanMsg->frame.data1 = RXB0D1;
                tempCanMsg->frame.data2 = RXB0D2;
                tempCanMsg->frame.data3 = RXB0D3;
                tempCanMsg->frame.data4 = RXB0D4;
                tempCanMsg->frame.data5 = RXB0D5;
                tempCanMsg->frame.data6 = RXB0D6;
                tempCanMsg->frame.data7 = RXB0D7;
                B0CONbits.RXFUL = 0;
                returnValue = 1;
            }
            break;
        case dB1CON_FIFO_POINTER_VALUE:
            if (B1CONbits.RXFUL != 0) //CheckB1
            {
                if ((RXB0SIDL & 0x08) == 0x08) //If Extended Message
                {
                    //message is extended
                    tempCanMsg->frame.idType = (uint8_t) dEXTENDED_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2ExtendedCANid(RXB0EIDH, RXB0EIDL, RXB0SIDH, RXB0SIDL);
                }
                else
                {
                    //message is standard
                    tempCanMsg->frame.idType = (uint8_t) dSTANDARD_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2StandardCANid(RXB0SIDH, RXB0SIDL);
                }

                tempCanMsg->frame.dlc   = RXB0DLC & 0x0F;
                tempCanMsg->frame.rtr   = RXB0DLC >> 6;
                tempCanMsg->frame.data0 = RXB0D0;
                tempCanMsg->frame.data1 = RXB0D1;
                tempCanMsg->frame.data2 = RXB0D2;
                tempCanMsg->frame.data3 = RXB0D3;
                tempCanMsg->frame.data4 = RXB0D4;
                tempCanMsg->frame.data5 = RXB0D5;
                tempCanMsg->frame.data6 = RXB0D6;
                tempCanMsg->frame.data7 = RXB0D7;
                B1CONbits.RXFUL = 0;
                returnValue = 1;
            }
            break;
        case dB2CON_FIFO_POINTER_VALUE:
            if (B2CONbits.RXFUL != 0) //CheckB2
            {
                if ((RXB0SIDL & 0x08) == 0x08) //If Extended Message
                {
                    //message is extended
                    tempCanMsg->frame.idType = (uint8_t) dEXTENDED_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2ExtendedCANid(RXB0EIDH, RXB0EIDL, RXB0SIDH, RXB0SIDL);
                }
                else
                {
                    //message is standard
                    tempCanMsg->frame.idType = (uint8_t) dSTANDARD_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2StandardCANid(RXB0SIDH, RXB0SIDL);
                }

                tempCanMsg->frame.dlc   = RXB0DLC & 0x0F;
                tempCanMsg->frame.rtr   = RXB0DLC >> 6;
                tempCanMsg->frame.data0 = RXB0D0;
                tempCanMsg->frame.data1 = RXB0D1;
                tempCanMsg->frame.data2 = RXB0D2;
                tempCanMsg->frame.data3 = RXB0D3;
                tempCanMsg->frame.data4 = RXB0D4;
                tempCanMsg->frame.data5 = RXB0D5;
                tempCanMsg->frame.data6 = RXB0D6;
                tempCanMsg->frame.data7 = RXB0D7;
                B2CONbits.RXFUL = 0;
                returnValue = 1;
            }
            break;
        case dB3CON_FIFO_POINTER_VALUE:
            if (B3CONbits.RXFUL != 0) //CheckB3
            {
                if ((RXB0SIDL & 0x08) == 0x08) //If Extended Message
                {
                    //message is extended
                    tempCanMsg->frame.idType = (uint8_t) dEXTENDED_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2ExtendedCANid(RXB0EIDH, RXB0EIDL, RXB0SIDH, RXB0SIDL);
                }
                else
                {
                    //message is standard
                    tempCanMsg->frame.idType = (uint8_t) dSTANDARD_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2StandardCANid(RXB0SIDH, RXB0SIDL);
                }

                tempCanMsg->frame.dlc   = RXB0DLC & 0x0F;
                tempCanMsg->frame.rtr   = RXB0DLC >> 6;
                tempCanMsg->frame.data0 = RXB0D0;
                tempCanMsg->frame.data1 = RXB0D1;
                tempCanMsg->frame.data2 = RXB0D2;
                tempCanMsg->frame.data3 = RXB0D3;
                tempCanMsg->frame.data4 = RXB0D4;
                tempCanMsg->frame.data5 = RXB0D5;
                tempCanMsg->frame.data6 = RXB0D6;
                tempCanMsg->frame.data7 = RXB0D7;
                B3CONbits.RXFUL = 0;
                returnValue = 1;
            }
            break;
        case dB4CON_FIFO_POINTER_VALUE:
            if (B4CONbits.RXFUL != 0) //CheckB4
            {
                if ((RXB0SIDL & 0x08) == 0x08) //If Extended Message
                {
                    //message is extended
                    tempCanMsg->frame.idType = (uint8_t) dEXTENDED_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2ExtendedCANid(RXB0EIDH, RXB0EIDL, RXB0SIDH, RXB0SIDL);
                }
                else
                {
                    //message is standard
                    tempCanMsg->frame.idType = (uint8_t) dSTANDARD_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2StandardCANid(RXB0SIDH, RXB0SIDL);
                }

                tempCanMsg->frame.dlc   = RXB0DLC & 0x0F;
                tempCanMsg->frame.rtr   = RXB0DLC >> 6;
                tempCanMsg->frame.data0 = RXB0D0;
                tempCanMsg->frame.data1 = RXB0D1;
                tempCanMsg->frame.data2 = RXB0D2;
                tempCanMsg->frame.data3 = RXB0D3;
                tempCanMsg->frame.data4 = RXB0D4;
                tempCanMsg->frame.data5 = RXB0D5;
                tempCanMsg->frame.data6 = RXB0D6;
                tempCanMsg->frame.data7 = RXB0D7;
                B4CONbits.RXFUL = 0;
                returnValue = 1;
            }
            break;
        case dB5CON_FIFO_POINTER_VALUE:
            if (B5CONbits.RXFUL != 0) //CheckB5
            {
                if ((RXB0SIDL & 0x08) == 0x08) //If Extended Message
                {
                    //message is extended
                    tempCanMsg->frame.idType = (uint8_t) dEXTENDED_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2ExtendedCANid(RXB0EIDH, RXB0EIDL, RXB0SIDH, RXB0SIDL);
                }
                else
                {
                    //message is standard
                    tempCanMsg->frame.idType = (uint8_t) dSTANDARD_CAN_MSG_ID_2_0B;
                    tempCanMsg->frame.id = convertReg2StandardCANid(RXB0SIDH, RXB0SIDL);
                }

                tempCanMsg->frame.dlc   = RXB0DLC & 0x0F;
                tempCanMsg->frame.rtr   = RXB0DLC >> 6;
                tempCanMsg->frame.data0 = RXB0D0;
                tempCanMsg->frame.data1 = RXB0D1;
                tempCanMsg->frame.data2 = RXB0D2;
                tempCanMsg->frame.data3 = RXB0D3;
                tempCanMsg->frame.data4 = RXB0D4;
                tempCanMsg->frame.data5 = RXB0D5;
                tempCanMsg->frame.data6 = RXB0D6;
                tempCanMsg->frame.data7 = RXB0D7;
                B5CONbits.RXFUL = 0;
                returnValue = 1;
            }
            break;
    }
		
    ECANCON = tempECANCON;
    return (returnValue);
}

uint8_t CAN_messagesInBuffer(void) {
    uint8_t messageCount = 0;
    if (RXB0CONbits.RXFUL != 0) //CheckRXB0
    {
        messageCount++;
    }
    if (RXB1CONbits.RXFUL != 0) //CheckRXB1
    {
        messageCount++;
    }
    if (B0CONbits.RXFUL_TXBIF != 0) //CheckB0
    {
        messageCount++;
    }
    if (B1CONbits.RXFUL_TXBIF != 0) //CheckB1
    {
        messageCount++;
    }
    if (B2CONbits.RXFUL_TXBIF != 0) //CheckB2
    {
        messageCount++;
    }
    if (B3CONbits.RXFUL_TXBIF != 0) //CheckB3
    {
        messageCount++;
    }
    if (B4CONbits.RXFUL_TXBIF != 0) //CheckB4
    {
        messageCount++;
    }
    if (B5CONbits.RXFUL_TXBIF != 0) //CheckB5
    {
        messageCount++;
    }
    return (messageCount);
}

uint8_t CAN_isBusOff(void)
{
    uint8_t returnValue = 0;

    //COMSTAT bit 5 TXBO: Transmitter Bus-Off bit
    //1 = Transmit error counter > 255
    //0 = Transmit error counter less then or equal to 255

    if (COMSTATbits.TXBO == 1) {
        returnValue = 1;
    }
    return (returnValue);
}

uint8_t CAN_isRXErrorPassive(void)
{
    uint8_t returnValue = 0;

    //COMSTAT bit 3 RXBP: Receiver Bus Passive bit
    //1 = Receive error counter > 127
    //0 = Receive error counter less then or equal to 127

    if (COMSTATbits.RXBP == 1) {
        returnValue = 1;
    }
    return (returnValue);
}

uint8_t CAN_isTXErrorPassive(void)
{
    uint8_t returnValue = 0;

    //COMSTAT bit 4 TXBP: Transmitter Bus Passive bit
    //1 = Transmit error counter > 127
    //0 = Transmit error counter less then or equal to 127

    if (COMSTATbits.TXBP == 1)
    {
        returnValue = 1;
    }
    return (returnValue);
}

/**
Internal functions
*/

static uint32_t convertReg2ExtendedCANid(uint8_t tempRXBn_EIDH, uint8_t tempRXBn_EIDL, uint8_t tempRXBn_SIDH, uint8_t tempRXBn_SIDL) {
    uint32_t returnValue = 0;
    uint32_t ConvertedID = 0;
    uint8_t CAN_standardLo_ID_lo2bits;
    uint8_t CAN_standardLo_ID_hi3bits;

    CAN_standardLo_ID_lo2bits = (uint8_t)(tempRXBn_SIDL & 0x03);
    CAN_standardLo_ID_hi3bits = (uint8_t)(tempRXBn_SIDL >> 5);
    ConvertedID = (uint32_t)(tempRXBn_SIDH << 3);
    ConvertedID = ConvertedID + CAN_standardLo_ID_hi3bits;
    ConvertedID = (ConvertedID << 2);
    ConvertedID = ConvertedID + CAN_standardLo_ID_lo2bits;
    ConvertedID = (ConvertedID << 8);
    ConvertedID = ConvertedID + tempRXBn_EIDH;
    ConvertedID = (ConvertedID << 8);
    ConvertedID = ConvertedID + tempRXBn_EIDL;
    returnValue = ConvertedID;
    return (returnValue);
}

static uint32_t convertReg2StandardCANid(uint8_t tempRXBn_SIDH, uint8_t tempRXBn_SIDL) {
    uint32_t returnValue = 0;
    uint32_t ConvertedID;
    //if standard message (11 bits)
    //EIDH = 0 + EIDL = 0 + SIDH + upper three bits SIDL (3rd bit needs to be clear)
    //1111 1111 111
    ConvertedID = (uint32_t)(tempRXBn_SIDH << 3);
    ConvertedID = ConvertedID + (uint32_t)(tempRXBn_SIDL >> 5);
    returnValue = ConvertedID;
    return (returnValue);
}

static void convertCANid2Reg(uint32_t tempPassedInID, uint8_t canIdType, uint8_t *passedInEIDH, uint8_t *passedInEIDL, uint8_t *passedInSIDH, uint8_t *passedInSIDL) {
    uint8_t wipSIDL = 0;

    if (canIdType == dEXTENDED_CAN_MSG_ID_2_0B)
    {
        //EIDL
        *passedInEIDL = 0xFF & tempPassedInID; //CAN_extendedLo_ID_TX1 = &HFF And CAN_UserEnter_ID_TX1
        tempPassedInID = tempPassedInID >> 8; //CAN_UserEnter_ID_TX1 = CAN_UserEnter_ID_TX1 >> 8

        //EIDH
        *passedInEIDH = 0xFF & tempPassedInID; //CAN_extendedHi_ID_TX1 = &HFF And CAN_UserEnter_ID_TX1
        tempPassedInID = tempPassedInID >> 8; //CAN_UserEnter_ID_TX1 = CAN_UserEnter_ID_TX1 >> 8

        //SIDL
        //push back 5 and or it
        wipSIDL = 0x03 & tempPassedInID;
        tempPassedInID = tempPassedInID << 3; //CAN_UserEnter_ID_TX1 = CAN_UserEnter_ID_TX1 << 3
        wipSIDL = (0xE0 & tempPassedInID) + wipSIDL;
        wipSIDL = (uint8_t)(wipSIDL + 0x08); // TEMP_CAN_standardLo_ID_TX1 = TEMP_CAN_standardLo_ID_TX1 + &H8
        *passedInSIDL = (uint8_t)(0xEB & wipSIDL); //CAN_standardLo_ID_TX1 = &HEB And TEMP_CAN_standardLo_ID_TX1

        //SIDH
        tempPassedInID = tempPassedInID >> 8;
        *passedInSIDH = 0xFF & tempPassedInID;
    }
    else //(canIdType == dSTANDARD_CAN_MSG_ID_2_0B)
    {
        *passedInEIDH = 0;
        *passedInEIDL = 0;
        tempPassedInID = tempPassedInID << 5;
        *passedInSIDL = 0xFF & tempPassedInID;
        tempPassedInID = tempPassedInID >> 8;
        *passedInSIDH = 0xFF & tempPassedInID;
    }
}

void ECAN_SetRXBnInterruptHandler(void (*handler)(void))
{
    RXBnInterruptHandler = handler;
}

void ECAN_RXBnI_ISR(void)
{
    RXBnInterruptHandler();
    PIR5bits.RXBnIF = 0;  // The ECAN hardware overrides the setting of this bit (to '1') when any receive buffer is not empty.
}

void ECAN_SetRXBnOverflowHandler(void (*handler)(void))
{
    RXBnOverflowHandler = handler;
}

void ECAN_SetBusOffHandler(void (*handler)(void))
{
    BusOffHandler = handler;
}

void ECAN_SetTXPassiveHandler(void (*handler)(void))
{
    TXPassiveHandler = handler;
}

void ECAN_SetRXPassiveHandler(void (*handler)(void))
{
    RXPassiveHandler = handler;
}

void ECAN_SetTXWarningHandler(void (*handler)(void))
{
    TXWarningHandler = handler;
}

void ECAN_SetRXWarningHandler(void (*handler)(void))
{
    RXWarningHandler = handler;
}

void ECAN_ERRI_ISR(void)
{
    if (COMSTATbits.RXB1OVFL)
    {
        RXBnOverflowHandler();
        COMSTATbits.RXB1OVFL = 0;  // In mode 2, this clears RXBnOVFL
    }
    
    if (COMSTATbits.TXBO)
    {
        BusOffHandler();
    }
    
    if (COMSTATbits.TXBP)
    {
        TXPassiveHandler();
    }
    
    if (COMSTATbits.RXBP)
    {
        RXPassiveHandler();
    }
    
    if (COMSTATbits.TXWARN)
    {
        TXWarningHandler();
    }
    
    if (COMSTATbits.RXWARN)
    {
        RXWarningHandler();
    }
    
    PIR5bits.ERRIF = 0;
}