/*********************************************************************
 *
 *              ECAN C Library Source Code
 *
 *********************************************************************
 * FileName:        ECANPoll.C
 * Dependencies:    p18cxxx.h/pic18.h, ECAN.h
 * Processor:       PIC18CXX8X
 * Compiler:        Microchip C 2.10.06 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * The software supplied herewith by Microchip Technology Incorporated
 * (the Company) for its PICmicro Microcontroller is intended and
 * supplied to you, the Companys customer, for use solely and
 * exclusively on Microchip PICmicro Microcontroller products. The
 * software is owned by the Company and/or its supplier, and is
 * protected under applicable copyright laws. All rights are reserved.
 * Any use in violation of the foregoing restrictions may subject the
 * user to criminal sanctions under applicable laws, as well as to
 * civil liability for the breach of the terms and conditions of this
 * license.
 *
 * THIS SOFTWARE IS PROVIDED IN AN AS IS CONDITION. NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 * Author               Date    Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Caio Gubel           5/5/03  ECAN Version 1.0 - Initial Release
 * Nilesh R.            7/22/03 Improved.
 * Nilesh R.            1/8/04  Renamed
 ********************************************************************/

#include "ecanpoll.h"

void _CANIDToRegs(BYTE* ptr,
                 unsigned long val,
                 BYTE type);
void _RegsToCANID(BYTE* ptr,
                 unsigned long *val,
                 BYTE type);

#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME) || \
      (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_FIXED) && (ECAN_FUNC_MODE_VAL == ECAN_MODE_2) )
    static BYTE* _ECANPointBuffer(BYTE b);
#endif

BYTE_VAL _ECANRxFilterHitInfo;

#define _SetStdRXFnValue(f, val)                                \
    ##f##SIDH = (long)ECAN_##f##_VAL >> 3L;                     \
    ##f##SIDL = (long)ECAN_##f##_VAL << 5L

#define _SetXtdRXFnValue(f, val)                                \
    ##f##SIDH = (long)ECAN_##f##_VAL >> 21L;                    \
    ##f##SIDL = (((long)ECAN_##f##_VAL >> 13L) & 0xe0) |        \
                    ((long)(ECAN_##f##_VAL) & 0x03L)   |        \
                    0x08;                                       \
    ##f##EIDH = (long)ECAN_##f##_VAL >> 8L;                     \
    ##f##EIDL = ECAN_##f##_VAL;


#define _SetStdRXMnValue(m, val)                                \
    RXM##m##SIDH = (long)ECAN_RXM##m##_VAL >> 3L;               \
    RXM##m##SIDL = (long)ECAN_RXM##m##_VAL << 5L

#define _SetXtdRXMnValue(m, val)                                \
    RXM##m##SIDH = (long)ECAN_RXM##m##_VAL >> 21L;              \
    RXM##m##SIDL = (((long)ECAN_RXM##m##_VAL >> 13L) & 0xe0) |  \
                    ((long)(ECAN_RXM##m##_VAL) & 0x03L);\
    RXM##m##EIDH = (long)ECAN_RXM##m##_VAL >> 8L;\
    RXM##m##EIDL = ECAN_RXM##m##_VAL;

#define RXF0            0
#define RXF1            1
#define RXF2            2
#define RXF3            3
#define RXF4            4
#define RXF5            5
#define RXF6            6
#define RXF7            7
#define RXF8            8
#define RXF9            9
#define RXF10           10
#define RXF11           11
#define RXF12           12
#define RXF13           13
#define RXF14           14
#define RXF15           15


/*
 * Compile-time validation ECAN options as per ECAN and ECAN rules.
 */
#if ( ECAN_SJW_VAL > 4 )
#error Invalid SJW value received.
#endif

#if ( ECAN_BRP_VAL > 64 )
#error Invalid BRP value received.
#endif

#if ( ECAN_PHSEG1_VAL > 8 )
#error Invalid PHSEG1 value received.
#endif

#if ( ECAN_PHSEG2_VAL > 8 )
#error Invalid PHSEG2 value received.
#endif

#if ( ECAN_PROPSEG_VAL > 8 )
#error Invalid PROPSEG value received.
#endif

// In Mode 1 & 2, double buffering on RXB0 is not available.


/*
 * In Mode 0, RXF0-RXF5 are always enabled.
 */
#if ( ECAN_FUNC_MODE_VAL == ECAN_MODE_0 )
    #undef ECAN_RXF0_MODE_VAL
    #define ECAN_RXF0_MODE_VAL      ECAN_RXF0_ENABLE

    #undef ECAN_RXF1_MODE_VAL
    #define ECAN_RXF1_MODE_VAL      ECAN_RXF1_ENABLE

    #undef ECAN_RXF2_MODE_VAL
    #define ECAN_RXF2_MODE_VAL      ECAN_RXF2_ENABLE

    #undef ECAN_RXF3_MODE_VAL
    #define ECAN_RXF3_MODE_VAL      ECAN_RXF3_ENABLE

    #undef ECAN_RXF4_MODE_VAL
    #define ECAN_RXF4_MODE_VAL      ECAN_RXF4_ENABLE

    #undef ECAN_RXF5_MODE_VAL
    #define ECAN_RXF5_MODE_VAL      ECAN_RXF5_ENABLE
#endif


/*********************************************************************
 * Function:        void ECANInitialize(void)
 *
 * Overview:        Use this function to initialize ECAN module with
 *                  options defined in ECAN.def file.
 *                  You may manually edit ECAN.def file as per your
 *                  requirements, or use Microchip Application
 *                  Maestro tool.
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    All pending transmissions are aborted.
 ********************************************************************/
void ECANInitialize(void)
{

    // Put module into Configuration mode.
    ECANSetOperationMode(ECAN_OP_MODE_CONFIG);


    // Set Bit rate values as per defines.
    BRGCON1 = ((ECAN_SJW_VAL-1) << 6) | (ECAN_BRP_VAL-1);
    BRGCON2 = (ECAN_PHSEG2_MODE_VAL << 7)      | \
              (ECAN_BUS_SAMPLE_MODE_VAL << 6)  | \
              ((ECAN_PHSEG1_VAL-1) << 3)       | \
              (ECAN_PROPSEG_VAL-1);
    BRGCON3 = (ECAN_WAKEUP_MODE_VAL << 7)      |
              (ECAN_FILTER_MODE_VAL << 6)      |
              (ECAN_PHSEG2_VAL-1);

    // Set CANTX2, TXDRIVE and CAN Capture modes.
    CIOCON = ECAN_TX2_SOURCE_VAL << 7           | \
             ECAN_TX2_MODE_VAL << 6         | \
             ECAN_TXDRIVE_MODE_VAL << 4        | \
             ECAN_CAPTURE_MODE_VAL;


    // Set WCAN functional mode.
    ECANCON_MDSEL1 = ECAN_FUNC_MODE_VAL >> 7;
    ECANCON_MDSEL0 = ECAN_FUNC_MODE_VAL >> 6;


    // Set RXB0 and RXB1 buffer modes.
#if ( ECAN_FUNC_MODE_VAL == ECAN_MODE_0 )
    RXB0CON = (ECAN_RXB0_MODE_VAL << 5) | (ECAN_RXB0_DBL_BUFFER_MODE_VAL << 2);
    RXB1CON = ECAN_RXB1_MODE_VAL << 5;
#else
    // In Mode1 & 2, Map 2-bit RXM bits into 1 RXM1 bit.
    #if ( ECAN_RXB0_MODE_VAL == ECAN_RECEIVE_ALL )
        RXB0CON = 0x40;
    #else
        RXB0CON = 0;
    #endif

    #if ( ECAN_RXB1_MODE_VAL == ECAN_RECEIVE_ALL )
        RXB1CON = 0x40;
    #else
        RXB1CON = 0;
    #endif
#endif

    // B0-B5 are available in Mode 1 and 2 only.
#if (ECAN_FUNC_MODE_VAL != ECAN_MODE_0)
    #if (ECAN_B0_TXRX_MODE_VAL != ECAN_BUFFER_TX)
        #if ( ECAN_B0_MODE_VAL == ECAN_RECEIVE_ALL )
            B0CON = 0x40;
        #else
            B0CON = 0;
        #endif
    #else
        B0CON = ECAN_B0_AUTORTR_MODE << 2;
    #endif

    #if (ECAN_B1_TXRX_MODE_VAL != ECAN_BUFFER_TX)
        #if ( ECAN_B1_MODE_VAL == ECAN_RECEIVE_ALL )
            B1CON = 0x40;
        #else
            B1CON = 0;
        #endif
    #else
        B1CON = ECAN_B1_AUTORTR_MODE << 2;
    #endif

    #if (ECAN_B2_TXRX_MODE_VAL != ECAN_BUFFER_TX)
        #if ( ECAN_B2_MODE_VAL == ECAN_RECEIVE_ALL )
            B2CON = 0x40;
        #else
            B2CON = 0;
        #endif
    #else
        B2CON = ECAN_B2_AUTORTR_MODE << 2;
    #endif

    #if (ECAN_B3_TXRX_MODE_VAL != ECAN_BUFFER_TX)
        #if ( ECAN_B3_MODE_VAL == ECAN_RECEIVE_ALL )
            B3CON = 0x40;
        #else
            B3CON = 0;
        #endif
    #else
        B3CON = ECAN_B3_AUTORTR_MODE << 2;
    #endif

    #if (ECAN_B4_TXRX_MODE_VAL != ECAN_BUFFER_TX)
        #if ( ECAN_B4_MODE_VAL == ECAN_RECEIVE_ALL )
            B4CON = 0x40;
        #else
            B4CON = 0;
        #endif
    #else
        B4CON = ECAN_B4_AUTORTR_MODE << 2;
    #endif

    #if (ECAN_B5_TXRX_MODE_VAL != ECAN_BUFFER_TX)
        #if ( ECAN_B5_MODE_VAL == ECAN_RECEIVE_ALL )
            B5CON = 0x40;
        #else
            B5CON = 0;
        #endif
    #else
        B5CON = ECAN_B5_AUTORTR_MODE << 2;
    #endif

    // Enable/disable buffers B0-B5.
    BSEL0 = ECAN_B5_TXRX_MODE_VAL << 7 | \
            ECAN_B4_TXRX_MODE_VAL << 6 | \
            ECAN_B3_TXRX_MODE_VAL << 5 | \
            ECAN_B2_TXRX_MODE_VAL << 4 | \
            ECAN_B1_TXRX_MODE_VAL << 3 | \
            ECAN_B0_TXRX_MODE_VAL << 2;
#endif




    // Assign value to RXF0 only if Mode0 is used or RXF0 itself is enabled.
#if ( (ECAN_RXF0_MODE_VAL == ECAN_RXFn_ENABLE) || (ECAN_FUNC_MODE_VAL == ECAN_MODE_0) )
    // Set Standard or Extended value.
    #if ( ECAN_RXF0_MSG_TYPE_VAL == ECAN_MSG_STD )
        _SetStdRXFnValue(RXF0, ECAN_RXF0_VAL);
    #else
        _SetXtdRXFnValue(RXF0, ECAN_RXF0_VAL);
    #endif
#endif

#if ( (ECAN_RXF1_MODE_VAL == ECAN_RXFn_ENABLE) || (ECAN_FUNC_MODE_VAL == ECAN_MODE_0) )
    #if ( ECAN_RXF1_MSG_TYPE_VAL == ECAN_MSG_STD )
        _SetStdRXFnValue(RXF1, ECAN_RXF1_VAL);
    #else
        _SetXtdRXFnValue(RXF1, ECAN_RXF1_VAL);
    #endif
#endif


#if ( (ECAN_RXF2_MODE_VAL == ECAN_RXFn_ENABLE) || (ECAN_FUNC_MODE_VAL == ECAN_MODE_0) )
    #if ( ECAN_RXF2_MSG_TYPE_VAL == ECAN_MSG_STD )
        _SetStdRXFnValue(RXF2, ECAN_RXF2_VAL);
    #else
        _SetXtdRXFnValue(RXF3, ECAN_RXF3_VAL);
    #endif
#endif


#if ( (ECAN_RXF3_MODE_VAL == ECAN_RXFn_ENABLE) || (ECAN_FUNC_MODE_VAL == ECAN_MODE_0) )
    #if ( ECAN_RXF3_MSG_TYPE_VAL == ECAN_MSG_STD )
        _SetStdRXFnValue(RXF3, ECAN_RXF3_VAL);
    #else
        _SetXtdRXFnValue(RXF3, ECAN_RXF3_VAL);
    #endif
#endif


#if ( (ECAN_RXF4_MODE_VAL == ECAN_RXFn_ENABLE) || (ECAN_FUNC_MODE_VAL == ECAN_MODE_0) )
    #if ( ECAN_RXF4_MSG_TYPE_VAL == ECAN_MSG_STD )
        _SetStdRXFnValue(RXF4, ECAN_RXF4_VAL);
    #else
        _SetXtdRXFnValue(RXF4, ECAN_RXF4_VAL);
    #endif
#endif

#if ( (ECAN_RXF5_MODE_VAL == ECAN_RXFn_ENABLE) || (ECAN_FUNC_MODE_VAL == ECAN_MODE_0) )
    #if ( ECAN_RXF5_MSG_TYPE_VAL == ECAN_MSG_STD )
        _SetStdRXFnValue(RXF5, ECAN_RXF4_VAL);
    #else
        _SetXtdRXFnValue(RXF5, ECAN_RXF5_VAL);
    #endif
#endif


    // Filters 6-15 are available in Modes 1 and 2 only.
#if (ECAN_FUNC_MODE_VAL != ECAN_MODE_0)
    #if ( ECAN_RXF6_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF6_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF6, ECAN_RXF6_VAL);
        #else
            _SetXtdRXFnValue(RXF6, ECAN_RXF6_VAL);
        #endif
    #endif

    #if ( ECAN_RXF7_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF7_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF7, ECAN_RXF7_VAL);
        #else
            _SetXtdRXFnValue(RXF7, ECAN_RXF7_VAL);
        #endif
    #endif

    #if ( ECAN_RXF8_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF8_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF8, ECAN_RXF9_VAL);
        #else
            _SetXtdRXFnValue(RXF8, ECAN_RXF9_VAL);
        #endif
    #endif

    #if ( ECAN_RXF9_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF9_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF9, ECAN_RXF9_VAL);
        #else
            _SetXtdRXFnValue(RXF9, ECAN_RXF9_VAL);
        #endif
    #endif

    #if ( ECAN_RXF10_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF10_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF10, ECAN_RXF10_VAL);
        #else
            _SetXtdRXFnValue(RXF10, ECAN_RXF10_VAL);
        #endif
    #endif

    #if ( ECAN_RXF11_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF11_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF11, ECAN_RXF11_VAL);
        #else
            _SetXtdRXFnValue(RXF11, ECAN_RXF11_VAL);
        #endif
    #endif

    #if ( ECAN_RXF12_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF12_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF12, ECAN_RXF12_VAL);
        #else
            _SetXtdRXFnValue(RXF12, ECAN_RXF12_VAL);
        #endif
    #endif

    #if ( ECAN_RXF13_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF13_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF13, ECAN_RXF13_VAL);
        #else
            _SetXtdRXFnValue(RXF13, ECAN_RXF13_VAL);
        #endif
    #endif

    #if ( ECAN_RXF14_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF14_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF14, ECAN_RXF14_VAL);
        #else
            _SetXtdRXFnValue(RXF14, ECAN_RXF14_VAL);
        #endif
    #endif

    #if ( ECAN_RXF15_MODE_VAL == ECAN_RXFn_ENABLE )
        #if ( ECAN_RXF15_MSG_TYPE_VAL == ECAN_MSG_STD )
            _SetStdRXFnValue(RXF15, ECAN_RXF15_VAL);
        #else
            _SetXtdRXFnValue(RXF15, ECAN_RXF15_VAL);
        #endif
    #endif
#endif

    // Enable/Disable filters in Modes 1 and 2 only.
#if ( ECAN_FUNC_MODE_VAL != ECAN_MODE_0 )
    RXFCON0 = (ECAN_RXF7_MODE_VAL << 7) | \
              (ECAN_RXF6_MODE_VAL << 6) | \
              (ECAN_RXF5_MODE_VAL << 5) | \
              (ECAN_RXF4_MODE_VAL << 4) | \
              (ECAN_RXF3_MODE_VAL << 3) | \
              (ECAN_RXF2_MODE_VAL << 2) | \
              (ECAN_RXF1_MODE_VAL << 1) | \
              (ECAN_RXF0_MODE_VAL);
    RXFCON1 = (ECAN_RXF15_MODE_VAL << 7) | \
              (ECAN_RXF14_MODE_VAL << 6) | \
              (ECAN_RXF13_MODE_VAL << 5) | \
              (ECAN_RXF12_MODE_VAL << 4) | \
              (ECAN_RXF11_MODE_VAL << 3) | \
              (ECAN_RXF10_MODE_VAL << 2) | \
              (ECAN_RXF9_MODE_VAL << 1)  | \
              (ECAN_RXF8_MODE_VAL);
#endif


    // Link each filter to corresponding buffer only if we are in Mode 1 or 2.
#if ( ECAN_FUNC_MODE_VAL != ECAN_MODE_0 )
    ECANLinkRXF0F1ToBuffer(ECAN_RXF0_BUFFER_VAL,     ECAN_RXF1_BUFFER_VAL);
    ECANLinkRXF2F3ToBuffer(ECAN_RXF2_BUFFER_VAL,     ECAN_RXF3_BUFFER_VAL);
    ECANLinkRXF4F5ToBuffer(ECAN_RXF4_BUFFER_VAL,     ECAN_RXF5_BUFFER_VAL);
    ECANLinkRXF6F7ToBuffer(ECAN_RXF6_BUFFER_VAL,     ECAN_RXF7_BUFFER_VAL);
    ECANLinkRXF8F9ToBuffer(ECAN_RXF8_BUFFER_VAL,     ECAN_RXF9_BUFFER_VAL);
    ECANLinkRXF10F11ToBuffer(ECAN_RXF10_BUFFER_VAL,  ECAN_RXF11_BUFFER_VAL);
    ECANLinkRXF12F13ToBuffer(ECAN_RXF12_BUFFER_VAL,  ECAN_RXF13_BUFFER_VAL);
    ECANLinkRXF14F15ToBuffer(ECAN_RXF14_BUFFER_VAL,  ECAN_RXF15_BUFFER_VAL);

    ECANLinkRXF0Thru3ToMask(ECAN_RXF0_MASK_VAL, \
                           ECAN_RXF1_MASK_VAL, \
                           ECAN_RXF2_MASK_VAL, \
                           ECAN_RXF3_MASK_VAL);
    ECANLinkRXF4Thru7ToMask(ECAN_RXF4_MASK_VAL, \
                           ECAN_RXF5_MASK_VAL, \
                           ECAN_RXF6_MASK_VAL, \
                           ECAN_RXF7_MASK_VAL);
    ECANLinkRXF8Thru11ToMask(ECAN_RXF8_MASK_VAL, \
                           ECAN_RXF9_MASK_VAL, \
                           ECAN_RXF10_MASK_VAL, \
                           ECAN_RXF11_MASK_VAL);
    ECANLinkRXF12Thru15ToMask(ECAN_RXF12_MASK_VAL, \
                           ECAN_RXF13_MASK_VAL, \
                           ECAN_RXF14_MASK_VAL, \
                           ECAN_RXF15_MASK_VAL);
#endif


#if ( ECAN_RXM0_MSG_TYPE == ECAN_MSG_STD )
    _SetStdRXMnValue(0, ECAN_RXM0_VAL);
    RXM0SIDL_EXIDEN = 0;
#else
    _SetXtdRXMnValue(0, ECAN_RXM0_VAL);
    RXM0SIDL_EXIDEN = 1;
#endif

#if ECAN_RXM1_MSG_TYPE == ECAN_MSG_STD
    _SetStdRXMnValue(1, ECAN_RXM1_VAL);
    RXM1SIDL_EXIDEN = 0;
#else
    _SetXtdRXMnValue(1, ECAN_RXM1_VAL);
    RXM1SIDL_EXIDEN = 1;
#endif

    // SDFLC value

    // Exit with speicfied mode.  If selected mode is Configuration,
    // we do not need to do anything.
#if ( ECAN_INIT_MODE != ECAN_INIT_CONFIGURATION )
    ECANSetOperationMode(ECAN_INIT_MODE);
#endif
}



/*********************************************************************
 * Function:        BOOL ECANLoadRTRBuffer(BYTE buffer,
 *                                         unsigned long id,
 *                                         BYTE *data,
 *                                         BYTE dataLen,
 *                                         BYTE type)
 *
 * Overview:        Use this function to update automatic RTR buffer.
 *
 *
 * PreCondition:    None
 *
 * Input:           buffer      - Buffer number that is to be loaded
 *                  id          - CAN message identifier.
 *                                Only 11 or 29 bits may be used
 *                                depending on standard or extended
 *                                message type as specified in
 *                                type parameter.
 *                  data        - Data bytes of upto 8 bytes in length
 *                  dataLen     - Data length from 0 thru 8.
 *                                If 0, data may be NULL.
 *                  type        - Buffer type
 *                                Must be ECAN_MSG_STD for Standard
 *                                        ECAN_MSG_XTD for Extended
 *
 * Output:          TRUE, if given data was successfully loaded
 *                  FALSE, if RTR buffer was in process of transmitting
 *                          automated response.
 *
 * Side Effects:    None
 *
 ********************************************************************/
#if ( defined(ECAN_ENABLE_AUTO_RTR) )
BOOL ECANLoadRTRBuffer(BYTE buffer,
                       unsigned long id,
                       BYTE *data,
                       BYTE dataLen,
                       BYTE type)
{
    BYTE *pBuffer;
    BYTE *pSavedBuffer;
    BYTE i;

    pSavedBuffer = pBuffer;

#if defined(ECAN_CHECKED_BUILD)
    // Make sure that this buffer is configured for RTR handling.
    if ( !((BYTE_VAL*)pBuffer)->bits.b2 )
        return FALSE;
#endif

    /*
     * Make sure that RTR response is not currently being transmitted.
     */
    if ( ((BYTE_VAL*)pBuffer)->bits.b4 )
        return FALSE;

    // Start with zero length.
    *(pBuffer+5) = 0;

    // Save given id into ID registers..
    _CANIDToRegs((BYTE*)(pBuffer+1), id, type);

    // Prepare for data byte access.
    pBuffer += 6;

    // Copy given number of data bytes.
    for ( i = 0; i < dataLen; i++ )
        *pBuffer++ = *data++;

    // At last, update DLC value.
    *(pSavedBuffer + 5) = dataLen;

    return TRUE;
}
#endif


/*********************************************************************
 * Function:        BOOL ECANSendMessage(unsigned long id,
 *                                      BYTE *data,
 *                                      BYTE dataLen,
 *                                      ECAN_TX_MSG_FLAGS msgFlags)
 *
 * Overview:        Use this function to transmit a CAN message.
 *                  This function searches for empty transmit buffer
 *                  and loads it with given messages. Buffer is then
 *                  marked for ready to transmit.
 *
 * PreCondition:    None
 *
 * Input:           id          - CAN message identifier.
 *                                Only 11 or 29 bits may be used
 *                                depending on standard or extended
 *                                message type as specified in
 *                                msgFlags parameter.
 *                  data        - Data bytes of upto 8 bytes in length
 *                  dataLen     - Data length from 0 thru 8.
 *                                If 0, data may be NULL.
 *                  msgFlags    - One or ECAN_TX_MSG_FLAGS values ORed
 *                                together
 *
 * Output:          TRUE, if an empty buffer was found and loaded with
 *                  given data
 *                  FALSE, if otherwise.
 *
 * Side Effects:    None
 *
 ********************************************************************/
BOOL ECANSendMessage( unsigned long id,
                     BYTE* data,
                     BYTE dataLen,
                     ECAN_TX_MSG_FLAGS msgFlags)
{
#if ( ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME )
    BYTE mode;
    BYTE buffers;
#elif ( ECAN_FUNC_MODE_VAL == ECAN_MODE_0 )
    #define buffers 2
#else
    #define buffers 8

#endif

    BYTE i,j;
    BYTE *ptr, *tempPtr;
    BYTE* pb[9];
    BYTE temp;

#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME) || (ECAN_FUNC_MODE_VAL != ECAN_MODE_0) )
    BYTE_VAL tempBSEL0;
#endif

    /*
     * Since there are more than one transmit buffers and they are scattered in
     * SFR map, prepare table of all transmit buffers.
     */
    pb[0]=(BYTE*)&TXB0CON;
    pb[1]=(BYTE*)&TXB1CON;
    pb[2]=(BYTE*)&TXB2CON;

    /*
     * Include programmable buffers only if mode 1 or 2 is used.
     */
#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME) || (ECAN_FUNC_MODE_VAL != ECAN_MODE_0) )

    pb[3]=(BYTE*)&B0CON;
    pb[4]=(BYTE*)&B1CON;
    pb[5]=(BYTE*)&B2CON;
    pb[6]=(BYTE*)&B3CON;
    pb[7]=(BYTE*)&B4CON;
    pb[8]=(BYTE*)&B5CON;
#endif

#if ( ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME )
    mode = ECANCON&0xC0;
    if ( mode == ECAN_MODE_0 )
        buffers = 2;
    else
        buffers = 8;
#endif


    /*
     * Depending on whether only mode 0 is used or not, we would only need to check
     * either 3 or all buffers.
     */

#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_FIXED) && (ECAN_FUNC_MODE_VAL == ECAN_MODE_0) )
    for ( i = 0; i < buffers; i++ )
#else



    /*
     * In Mode 1 & 2, programmable buffers must be checked for buffer mode.
     * By remembering BSEL0 (programmable buffer mode type info), we can
     * reduce code required to check invidual buffer type as we scan through
     * all buffers.
     */
    tempBSEL0.Val = BSEL0 >> 1;

    for ( i = 0; i < buffers; i++ )
#endif
    {
        /*
         * Use local poiter to reduce overall code.
         * It will be more efficient to access using pointer instead of index.
         */
        ptr = pb[i];
        tempPtr = ptr;


        /*
         * In Mode 1 & 2, if buffer number is above TXB2, we must also check to
         * see if this buffer is configured for transmit mode.
         */
#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME) || (ECAN_FUNC_MODE_VAL != ECAN_MODE_0) )
        if ( i > 2 )
        {
            /*
             * Use previously saved BSEL0 value.
             */
            tempBSEL0.Val >>= 1;

            /*
             * If this is not transmit buffer, continue with next buffer.
             */
            if ( !tempBSEL0.bits.b0 )
                continue;
        }
#endif

        /*
         * Check to see if this buffer is empty by looking at BnCON.TXREQ bit (bit3).
         */
        if ( !(*ptr & 0x08) )
        {
            // Set transmit priority in BnCON register.
            *ptr &= ~ECAN_TX_PRIORITY_BITS;
            *ptr |= msgFlags & ECAN_TX_PRIORITY_BITS;

            // Also save DLC value.
            if ( msgFlags & ECAN_TX_RTR_BIT )
                temp = 0x40 | dataLen;
            else
                temp = dataLen;
            // Use temp to reduce evaluation of *(ptr+5) to only once.
            *(ptr+5) = temp;

            // Set standard or extended message type.
            if ( msgFlags & ECAN_TX_FRAME_BIT )
                temp = ECAN_MSG_XTD;

            else
                temp = ECAN_MSG_STD;

            // And rearrange given id accordingly.
            _CANIDToRegs((BYTE*)(ptr+1), id, temp);

            // Prepare for data byte access.
            ptr += 6;
            // Copy given number of data bytes.
            for ( j = 0 ; j < dataLen; j++ )
                *ptr++ = *data++;

            // If this buffer is configured to automatically handle RTR messages,
            // do not set TXREQ bit.  TXREQ bit will be set whenever matching RTR is received.
            if ( !(*tempPtr & 0x04) )
                *tempPtr |= 0x08;

            return TRUE;
        }
    }

    // There were no empty buffers.
    return FALSE;
}



/*********************************************************************
 * Function:        BOOL ECANReceiveMessage(unsigned long *id,
 *                                  BYTE *data,
 *                                  BYTE *dataLen,
 *                                  ECAN_RX_MSG_FLAGS *msgFlags)
 *
 * Overview:        Use this function to check for full receive buffer
 *                  and extract received data into local buffers.
 *
 * PreCondition:    None
 *
 * Input:           id          - Pointer to buffer that will be
 *                                populated with receive ID.
 *                  data        - Pointer to buffer that will be
 *                                populated with data if there is any
 *                  dataLen     - Pointer to buffer that will be
 *                                populated with count of bytes
 *                                copied in data buffer.
 *                  msgFlags    - Pointer to buffer that will be
 *                                copied with information about
 *                                received message. More than
 *                                one information is ORed together.
 *
 * Output:          TRUE, if a full receive buffer was found and
 *                  given parameters were populated.
 *                  FALSE, if otherwise.
 *
 * Side Effects:    None
 *
 * Note:            If you need to know the filter number that caused
 *                  this message to get accepted, call
 *                  ECANGetFilterHitInfo().
 *
 ********************************************************************/
BOOL ECANReceiveMessage(unsigned long *id,
                       BYTE *data,
                       BYTE *dataLen,
                       ECAN_RX_MSG_FLAGS *msgFlags)
{
#if ( ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME )
    BYTE mode;
#endif

    BYTE *ptr, *savedPtr;
    char i;
    BYTE_VAL temp;

    _ECANRxFilterHitInfo.Val = 0;

#if ( ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME )
    mode = ECANCON&0xC0;
    if ( mode == ECAN_MODE_0 )
#endif


#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME) || \
      (ECAN_LIB_MODE_VAL == ECAN_LIB_FIXED) && (ECAN_FUNC_MODE_VAL == ECAN_MODE_0) )
    {
        // Find which buffer is ready.
        if ( RXB0CON_RXFUL )
        {
            // Clear the received flag.
            PIR3_RXB0IF = 0;

            // Record and forget any previous overflow
            if ( COMSTAT_RXB0OVFL )
            {
                *msgFlags |= ECAN_RX_OVERFLOW;
                COMSTAT_RXB0OVFL = 0;
            }

            _ECANRxFilterHitInfo.bits.b0 = RXB0CON_FILHIT0;

            ptr = (BYTE*)&RXB0CON;

        }
        else if ( RXB1CON_RXFUL )
        {
            // Clear the received flag.
            PIR3_RXB1IF = 0;

            // Record and forget any previous overflow
            if ( COMSTAT_RXB1OVFL )
            {
                *msgFlags |= ECAN_RX_OVERFLOW;
                COMSTAT_RXB1OVFL = 0;
            }

            _ECANRxFilterHitInfo.Val = RXB1CON & 0x07;

            if ( _ECANRxFilterHitInfo.Val < 0x02 )
                *msgFlags |= ECAN_RX_DBL_BUFFERED;


            ptr = (BYTE*)&RXB1CON;
        }
        else
            return FALSE;

        goto _SaveMessage;
    }
#endif

#if ( ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME )
    else if ( mode == ECAN_MODE_1 )
#endif

#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME) || \
      (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_FIXED) && (ECAN_FUNC_MODE_VAL == ECAN_MODE_1) )

    {
        if ( RXB0CON_RXFUL )
            ptr = (BYTE*)&RXB0CON;

        else if (RXB1CON_RXFUL)
            ptr = (BYTE*)&RXB1CON;

        else if ( (BSEL0_B0TXEN==0) && B0CON_RXFUL )
            ptr = (BYTE*)&B0CON;

        else if ( (BSEL0_B1TXEN==0) && B1CON_RXFUL )
            ptr = (BYTE*)&B1CON;

        else if ( (BSEL0_B2TXEN==0) && B2CON_RXFUL )
            ptr = (BYTE*)&B2CON;

        else if ( (BSEL0_B3TXEN==0) && B3CON_RXFUL )
            ptr = (BYTE*)&B3CON;

        else if ( (BSEL0_B4TXEN==0) && B4CON_RXFUL )
            ptr = (BYTE*)&B4CON;

        else if ( (BSEL0_B5TXEN==0) && B5CON_RXFUL )
            ptr = (BYTE*)&B5CON;

        else
            return FALSE;

        goto _SaveMode12Message;


    }
#endif

#if ( ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME )
    else
#endif

#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME) || \
      (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_FIXED) && (ECAN_FUNC_MODE_VAL == ECAN_MODE_2) )
    {
        if ( COMSTAT_FIFOEMPTY == 1 )      //if FIFO is NOT empty --> meaning there is a message to be read waiting in Bn or RXBn Buffer
        {
            ptr = (BYTE*)_ECANPointBuffer(CANCON&0x07);          // get the pointer to the proper buffer

            goto _SaveMode12Message;
        }

        return FALSE;
    }
#endif


#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME) || (ECAN_FUNC_MODE_VAL != ECAN_MODE_0) )
_SaveMode12Message:
    _ECANRxFilterHitInfo.Val = *ptr & 0x1f;

    PIR3_RXBnIF = 0;

    if ( COMSTAT_RXBnOVFL )
    {
        *msgFlags |= ECAN_RX_OVERFLOW;
        COMSTAT_RXBnOVFL = 0;
    }
#endif

_SaveMessage:
    savedPtr = ptr;
    *msgFlags = 0;

    // Retrieve message length.
    temp.Val = *(ptr+5);
    *dataLen = temp.Val & 0b00001111;

    // Determine whether this was RTR or not.
    if ( temp.bits.b6 )
        *msgFlags |= ECAN_RX_RTR_FRAME;

    // Retrieve EIDX bytes only if this is extended message
    temp.Val = *(ptr+2);
    if ( temp.bits.b3 )
    {
        *msgFlags |= ECAN_RX_XTD_FRAME;
        temp.Val = ECAN_MSG_XTD;
    }
    else
        temp.Val = ECAN_MSG_STD;

    _RegsToCANID(ptr+1, id, temp.Val);

    // Get message data itself
    ptr += 6;
    temp.Val = *dataLen;
    for ( i = 0; i < temp.Val; i++ )
        *data++ = *ptr++;

    // Record and Clear any previous invalid message bit flag.
    if ( PIR3_IRXIF )
    {
        *msgFlags |= ECAN_RX_INVALID_MSG;
        PIR3_IRXIF = 0;
    }

    // Mark that this buffer is read and empty.
    *savedPtr &= 0x7f;

#if ( ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME )
    // Workaround for Rev A1 silicon
    if ( mode == ECAN_MODE_2 )
    {
        COMSTAT_FIFOEMPTY = 0;
        COMSTAT_FIFOEMPTY = 0;
    }

#elif ( ECAN_FUNC_MODE_VAL == ECAN_MODE_2 )
    COMSTAT_FIFOEMPTY = 0;
    COMSTAT_FIFOEMPTY = 0;
#endif

    return TRUE;
}

/*********************************************************************
 * Function:        void ECANSetOperationMode(ECAN_OP_MODE mode)
 *
 * Overview:        Use this function to switch ECAN module into
 *                  given operational mode.
 *
 * PreCondition:    None
 *
 * Input:           mode    - Operation mode code
 *                            must be of type ECAN_OP_MODES
 *
 * Output:          MCU is set to requested mode
 *
 * Side Effects:    None
 *
 * Note:            This is a blocking call.  It will not return until
 *                  requested mode is set.
 ********************************************************************/
void ECANSetOperationMode(ECAN_OP_MODE mode)
{
    CANCON &= 0x1F;                         // clear previous mode
    CANCON |= mode;                         // set new mode

    while( ECANGetOperationMode() != mode ); // Wait till desired mode is set.
}


/*********************************************************************
 * Function:        void _CANIDToRegs(BYTE* ptr,
 *                                    unsigned long val,
 *                                    ECAN_MSG_TYPE type)
 *
 * PreCondition:    None
 *
 * Input:           ptr     - Starting address of a buffer to be updated
 *                  val     - 32-bit value to be converted
 *                  type    - Type of message - either
 *                            CAN_CONFIG_XTD_MSG or CAN_CONFIG_STD_MSG
 *
 * Output:          Given CAN id value 'val' is bit adjusted and copied
 *                  into corresponding PIC18CXX8 CAN registers
 *
 * Side Effects:    None
 *
 * Overview:        If given id is of type standard identifier,
 *                  only SIDH and SIDL are updated
 *                  If given id is of type extended identifier,
 *                  bits val<17:0> is copied to EIDH, EIDL and SIDH<1:0>
 *                  bits val<28:18> is copied to SIDH and SIDL
 *
 ********************************************************************/
//////////////////////////////////////////////////////////////////////

/*********************************************************************
 *
 * union CAN_MESSAGE_ID
 *
 * This union provides abstract data type for CAN message id.
 * It is used for both 11-bit and 29-bit message identifiers.
 * There are multiple union members to be able to access individual
 * parts of it.
 *
 ********************************************************************/
 // Parse-out 29-bit or 11-bit (saved in 32-bit number)
typedef union _CAN_MESSAGE_ID
{
    unsigned long ID;

    struct
    {
        struct
        {
            unsigned SIDL:3;        // SIDL<5:7>
            unsigned SIDH:5;        // SIDH<0:4>
        } BYTE1;
        struct
        {
            unsigned SIDHU:3;       // SIDH<5:7>
            unsigned EIDL_LN:5;     // EIDL<0:4>
        } BYTE2;
        struct
        {
            unsigned EIDL_UN:3;     // EIDL<5:7>
            unsigned EIDH_LN:5;     // EIDH<0:4>
        } BYTE3;
        struct
        {
            unsigned EIDH_UN:3;     // EIDH<5:7>
            unsigned EIDHU:2;       // SIDL<0:1>
            unsigned :3;
        } BYTE4;
    } ID_VALS;

    // This is to allow individual byte access within message id.
    struct
    {
        BYTE BYTE_1;
        BYTE BYTE_2;
        BYTE BYTE_3;
        BYTE BYTE_4;
    } BYTES;
} CAN_MESSAGE_ID;

void _CANIDToRegs(BYTE* ptr,
                  unsigned long val,
                  BYTE type)
{
    CAN_MESSAGE_ID *Value;

    Value =  (CAN_MESSAGE_ID*)&val;

    if ( type == ECAN_MSG_STD )
    {
        // Standard Identifier
        *ptr = Value->BYTES.BYTE_1 >> 3;        // Copy SID<7:3> to SIDH<4:0>
        *ptr |= (Value->BYTES.BYTE_2 << 5);     // Copy SID<10:8> to SIDH<7:5>
        ptr++;                                  // Point to SIDL
        *ptr = Value->BYTES.BYTE_1 << 5;        // Copy SID<2:0> to SIDL<7:5>
    }
    else
    {
        // Extended Identifier
        *ptr = Value->BYTES.BYTE_3 >> 5;        // Copy EID<23:21> to SIDH<2:0>
        *ptr |= Value->BYTES.BYTE_4 << 3;       // Copy EID<28:24> to SIDH<7:3>
        ptr++;                                  // Point to SIDL
        *ptr = (Value->BYTES.BYTE_3 << 3) & 0xE0; // Copy EID<20:18> to SIDL<7:5>
                                                // mask out EID<17:16> bits
        *ptr |= 0b00001000;                     // Set EXIDEN bit  to SIDL<3>
        *ptr |= Value->BYTES.BYTE_3 & 0x03;     // Copy EID<17:16> to SIDL<1:0>
        ptr++;                                  // Point to EIDH
        *ptr = Value->BYTES.BYTE_2;             // Copy EID<15:8> to EIDH<7:0>
        ptr++;                                  // Point to EIDL
        *ptr = Value->BYTES.BYTE_1;             // Copy EID<7:0> to EIDL<7:0>
    }
}

/*********************************************************************
 * Function:        void _RegsToCANID(BYTE *ptr,
 *                                   unsigned long *val,
 *                                   BYTE type)
 *
 * PreCondition:    None
 *
 * Input:           ptr     - Starting address of a buffer to be updated
 *                  val     - 32-bit buffer to hold value
 *                  type    - Type of message - either
 *                            CAN_CONFIG_XTD_MSG or CAN_CONFIG_STD_MSG
 *
 * Output:          CAN registers starting at given address are bit
 *                  adjusted and copied into 'val'
 *
 * Side Effects:    None
 *
 * Overview:        If given id is of type standard identifier,
 *                  only SIDH and SIDL are used
 *                  If given id is of type extended identifier,
 *                  bits EIDH, EIDL and SIDL<1:0> is copied to val<17:0>
 *                  bits SIDH and SIDL is copied to val<28:18>
 *
 ********************************************************************/
void _RegsToCANID( BYTE* ptr,
                   unsigned long *val,
                   BYTE type )
{
    CAN_MESSAGE_ID *Value;

    Value = (CAN_MESSAGE_ID*)val;

    if ( type == ECAN_MSG_STD )
    {
        // Standard Identifier
        Value->BYTES.BYTE_1 = (*ptr << 3);      // Copy SIDH<4:0> to SID<7:3>
        Value->BYTES.BYTE_2 = *ptr >> 5;        // Copy SIDH<7:5> to SID<10:8>
        ptr++;                                  // Point to SIDL
        Value->BYTES.BYTE_1 |= (*ptr >> 5);     // Copy SIDL<7:6> to SID<2:0>
        Value->BYTES.BYTE_3 = 0x00;
        Value->BYTES.BYTE_4 = 0x00;
    }
    else
    {
        // Extended Identifier
        Value->BYTES.BYTE_3 = (*ptr << 5);      // Copy SIDH<2:0> to EID<23:21>
        Value->BYTES.BYTE_4 = (*ptr >> 3);      // Copy SIDH<7:3> to EID<29:25>
        ptr++;                          // Point to SIDL
        Value->BYTES.BYTE_3 |= (*ptr & 0x03);   // Copy SIDH<1:0> to EID<17:16>
        // Bug-Fix NKR 11/20/00
        Value->BYTES.BYTE_3 |= ((*ptr & 0xe0) >> 3);  // Copy SIDL<7:6> to EID<20:18>
        ptr++;                          // Point to EIDH
        Value->BYTES.BYTE_2 = *ptr;             // Copy EIDH<15:8> to EID<15:8>
        ptr++;                                  // Point to EIDL
        Value->BYTES.BYTE_1 = *ptr;             // Copy EIDH<7:0> to EID<7:0>
    }
}


/*********************************************************************
 * Function:        BYTE* _ECANPointBuffer(BYTE b)
 *
 * PreCondition:    None
 *
 * Input:           buffer number
 *
 * Output:          RXBnCON or RnCON address
 *
 * Side Effects:    None
 *
 * Overview:        This functions returns a pointer to the
 *                  beginning of a reception buffer
 *
 * Note:
 ********************************************************************/
#if ( (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_RUN_TIME) || \
      (ECAN_LIB_MODE_VAL == ECAN_LIB_MODE_FIXED) && (ECAN_FUNC_MODE_VAL == ECAN_MODE_2) )
static BYTE* _ECANPointBuffer(BYTE b)
{
    BYTE* pt;

    switch(b)
    {
    case 0:
        pt=(BYTE*)&RXB0CON;     // return pointer to correct buffer
        break;
    case 1:
        pt=(BYTE*)&RXB1CON;
        break;
    case 2:
        pt=(BYTE*)&B0CON;
        break;
    case 3:
        pt=(BYTE*)&B1CON;
        break;
    case 4:
        pt=(BYTE*)&B2CON;
        break;
    case 5:
        pt=(BYTE*)&B3CON;
        break;
    case 6:
        pt=(BYTE*)&B4CON;
        break;
    default:              //case 7:
        pt=(BYTE*)&B5CON;
        break;
    }
    return (pt);
}
#endif



