#define CANROU_SOURCE
	
	#include <p18F258.inc>
	#include "CANDef.inc"
	
; 	CAN routines in assembly code  

CANROU_start	CODE


;****************************************************************************
;* Function:            void CANInitializeFunc(BYTE SJW,
;*                      BYTE BRP,
;*                      BYTE PHSEG1,
;*                      BYTE PHSEG2,
;*                      BYTE PROPSEG,
;*                      enum CAN_CONFIG_FLAGS flags)
;*
;* Input:               m_SJW - SJW value as defined in 18CXX8 datasheet
;*                      (Must be between 1 thru 4)
;*                      m_BRP - BRP value as defined in 18CXX8 datasheet
;*                      (Must be between 1 thru 64)
;*                      m_PHSEG1 - PHSEG1 value as defined in 18CXX8 datasheet
;*                      Must be between 1 thru 8)
;*                      m_PHSEG2 - PHSEG2 value as defined in 18CXX8 datasheet
;*                      (Must be between 1 thru 8)
;*                      m_PROPSEG2 - PROPSEG value as defined in 18CXX8
;*                      datasheet
;*                      (Must be between 1 thru 8)
;*                      m_Flags1 - Value of type enum CAN_CONFIG_FLAGS
;*
;* Output:              CAN bit rate is set. All masks registers are set
;*                      '0' to allow all messages.
;*                      Filter registers are set according to flag value.
;*                      If (config & CAN_CONFIG_VALID_XTD_MSG)
;*                      Set all filters to XTD_MSG
;*                      Else if (config & CONFIG_VALID_STD_MSG)
;*                      Set all filters to STD_MSG
;*                      Else
;*                      Set half of the filters to STD while rests to
;*                      XTD_MSG.
;*
;* Side Effects:        All pending transmissions are aborted.
;*
;****************************************************************************

CANInitializeFunc
	GLOBAL CANInitializeFunc
;	Set configuration mode
        CANSetOperationMode     CAN_OP_MODE_CONFIG      ;
        call    CANSetBaudRateFunc

        movlw   CAN_CONFIG_MSG_BITS
        andwf   m_Flags1,W
        movwf   RXB0CON         ;Load Rx Buffer 0 Control reg.
        btfsc   m_Flags1,CAN_CONFIG_DBL_BUFFER_BIT_NO
        bsf     RXB0CON,RXB0DBEN ;Set double Buffer Enable bit

        movff   RXB0CON,RXB1CON ;Load same configuration in Rx Buffer 1
                                ;control register

        CANSetReg_IF    CAN_MASK_B0, 0, m_Flags1        ;Set Mask B0
        CANSetReg_IF    CAN_MASK_B1, 0, m_Flags1        ;Set Mask B1
        CANSetReg_IF    CAN_FILTER_B0_F1, 0, m_Flags1   ;Set Filter 1
        CANSetReg_IF    CAN_FILTER_B0_F2, 0, m_Flags1   ;Set Filter 2
        CANSetReg_IF    CAN_FILTER_B1_F1, 0, m_Flags1   ;Set Filter 3
        CANSetReg_IF    CAN_FILTER_B1_F2, 0, m_Flags1   ;Set Filter 4
        CANSetReg_IF    CAN_FILTER_B1_F3, 0, m_Flags1   ;Set Filter 5
        CANSetReg_IF    CAN_FILTER_B1_F4, 0, m_Flags1   ;Set Filter 6

; Restore to Normal mode.
        CANSetOperationMode     CAN_OP_MODE_NORMAL      ;
        banksel TxBufSize
        clrf    TxBufSize       ;Clear Tx Buffer data counter

#ifdef  CANIntLowPrior
        bsf     RCON,IPEN       ;Enable Priority levels on Int.
        movlw   B'11100011'
        andwf   IPR3,F          ;Set low priority for Tx. Int.
#else
        movlw   B'00011100'
        iorwf   IPR3,F          ;Set high priority for Tx. Int. (Default)
#endif

        bsf     INTCON,GIE      ;Enable global Interrupt
        bsf     INTCON,PEIE     ;Enable Peripheral Interrupt

        return


;****************************************************************************
;* Function:            void CANSetOperationModeFunc(CAN_OP_MODE mode)
;*
;* PreCondition:        None
;*
;* Input:               W reg   - Operation mode code
;*
;*
;* Output:              MCU is set to requested mode
;*
;* Side Effects:        Databank is changed
;*
;* Overview:            Given mode byte is copied to CANSTAT and made
;*                      sure that requested mode is set.
;*
;* Note:                This is a blocking call.  It will not return until
;*                      requested mode is set.
;****************************************************************************

CANSetOperationModeFunc
	GLOBAL 	CANSetOperationModeFunc
        movwf   CANCON          ;Request desired mode
        movwf   Temp1           ;Store value in Temp reg. for future

ChkModeSet:
        movlw   CAN_OP_MODE_BITS
	andwf   CANSTAT,W       ;Chk CAN status register
        xorwf   Temp1,W
	BSF	STATUS,Z
        bnz     ChkModeSet      ;Wait till desired mode is set

        return


;****************************************************************************
;* Function:            void CANSetBaudRateFunc(BYTE SJW,
;*                                              BYTE BRP,
;*                                              BYTE PHSEG1,
;*                                              BYTE PHSEG2,
;*                                              BYTE PROPSEG,
;*                                              enum CAN_CONFIG_FLAGS flags)
;*
;* PreCondition:        MCU must be in Configuration mode or else these
;*                      values will be ignored.
;*
;* Input:               m_SJW   - SJW value as defined in 18CXX8 datasheet
;*                              (Must be between 1 thru 4)
;*                      m_BRP   - BRP value as defined in 18CXX8 datasheet
;*                              (Must be between 1 thru 64)
;*                      m_PHSEG1 - PHSEG1 value as defined in 18CXX8
;*                               datasheet
;*                              (Must be between 1 thru 8)
;*                      m_PHSEG2 - PHSEG2 value as defined in 18CXX8
;*                               datasheet
;*                              (Must be between 1 thru 8)
;*                      m_PROPSEG - PROPSEG value as defined in 18CXX8
;*                               datasheet
;*                              (Must be between 1 thru 8)
;*                              flags   - Value of type enum CAN_CONFIG_FLAGS
;*
;* Output:              CAN bit rate is set as per given values.
;*
;* Side Effects:        Databank is changed
;*
;* Overview:            Given values are bit adjusted to fit in 18CXX8
;*                      BRGCONx registers and copied.
;*
;****************************************************************************

CANSetBaudRateFunc
	GLOBAL 	CANSetBaudRateFunc
        movff   m_SJW,Temp1
        decf    Temp1,F         ;Align values for offfset from 0
        movlw   0x40            ;Multiply by 40H to align the bits
        mulwf   Temp1           ;for BRGCON1 requirement
        movff   PRODL,Temp1     ;Transfer Result to Temp1

        movlw   0xc0
        andwf   Temp1,F         ;Mask bits
        banksel m_BRP
        decf    m_BRP,W         ;Align values for offset from 0
        iorwf   Temp1,W         ;Calculate value for BRGCON1
        movwf   BRGCON1         ;Transfer value to BRGCON1

        movff   m_PHSEG1,Temp1
        decf    Temp1,F
        rlncf   Temp1,F         ;Align the bits
        rlncf   Temp1,F
        rlncf   Temp1,W
        banksel m_PROPSEG2
        decf    m_PROPSEG2,F    ;Align values for offset 0
        iorwf   m_PROPSEG2,W    ;Calculate value for BRGCON2
        movwf   BRGCON2         ;Transfer value to BRGCON2
        btfsc   m_Flags1,CAN_CONFIG_PHSEG2_PRG_BIT_NO
        bsf     BRGCON2,SEG2PHTS        ;Set SEG2PHTS
        btfsc   m_Flags1,CAN_CONFIG_SAMPLE_BIT_NO
        bsf     BRGCON2,SAM     ;Set SEG2PHTS

        movff   m_PHSEG2,BRGCON3        ;Transfer PHSEG2 value to BRGCON3
        decf    BRGCON3,F
        btfsc   m_Flags1,CAN_CONFIG_LINE_FILTER_BIT_NO
        bsf     BRGCON3,WAKFIL  ;Set WAKFIL bit

        return


;****************************************************************************
;* Function:            CANISetRegfunc  RegAddr,
;*                                      unsigned long val,
;*                                      CAN_CONFIG_FLAGS type
;*
;* PreCondition:        None
;*
;* Input:               FSR0H:FSR0L - Starting address of a 32-bit buffer to
;*                                      be updated
;*                      Reg1:Reg1+3 - 32-bit value to be converted
;*                      (Reg1= LL, Reg1+1 =LH, Reg1+2 = HL and Reg1+3 = HH
;*                       byte)
;*                      m_Flags1 - Type of message Flag - 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:        Databank changed
;*
;* 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
;*
;****************************************************************************

CANSetRegFunc
	GLOBAL	CANSetRegFunc
        banksel m_Flags1
        btfss   m_Flags1,CAN_CONFIG_MSG_TYPE_BIT_NO
        bra     SetExtFram

        movlw   0x05            ;Rotetae Left 5 times the 32 bit number
        rcall   RotateLeft32N
        movff   Reg1+1,POSTINC0
        banksel Reg1
        movlw   0xe0
        andwf   Reg1,W
        movwf   INDF0
        return

SetExtFram
        movlw   0x03            ;Rotetae Left 5 times the 32 bit number
        rcall   RotateLeft32N
        movff   Reg1+3,POSTINC0 ;Set EID<28:21>
        movff   Reg1+2,INDF0    ;Set EID <20:18>

        movlw   0x03            ;Rotetae Right 5 times the 32 bit number
        rcall   RotateRight32N  ;to restore original number
        movlw   0xe0            ;Mask other bits except EID<20:18>
        andwf   INDF0,F
        bsf     INDF0,EXIDE     ;Set  EXIDE bit
        movlw   0x03
        andwf   Reg1+2,W
        iorwf   POSTINC0,F      ;Set EID<17:16>

        movff   Reg1+1,POSTINC0
        movff   Reg1,POSTINC0

        return


;****************************************************************************
;* Function:            RotateLeft32N
;*
;*
;* PreCondition:        None
;*
;* Input:               W reg: Value for total rotation required
;*
;*                      Reg1:Reg1+3 - 32-bit value to be converted
;*                      (Reg1= LL, Reg1+1 =LH, Reg1+2 = HL and Reg1+3 = HH
;*                       byte)
;*
;* Output:              32 bit value in Reg1 shifted left by value in W times
;*
;* Side Effects:        Data Bank changed
;*
;* Overview:            It shifts 32-bit value in Reg1 by W times and returns
;*                      result in Reg1
;*
;****************************************************************************

RotateLeft32N

        banksel Reg1

RotateLMore:
        bcf     STATUS,C
        btfsc   Reg1+3,7        ;Pre-read bit 31 to be copied into
        bsf     STATUS,C        ;Bit 0

        rlcf    Reg1,F
        rlcf    Reg1+1,F
        rlcf    Reg1+2,F
        rlcf    Reg1+3,F
        decfsz  WREG,F
        bra     RotateLMore

        return


;*********************************************************************
;* Function:            CANIReadReg     RegAddr,
;*                                      Val,
;*                                      CAN_CONFIG_FLAGS type
;*
;* PreCondition:        None
;*
;* Input:               FSR0 - Starting address of a 32-bit buffer to be
;*                              read
;*                      FSR1 - Starting address of a memory location to
;*                              copy read 32 bit value
;*                      m_Flags1 - 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:        Databank changed
;*
;* Overview:            If given id is of type standard identifier,
;*                      only SIDH and SIDL are read
;*                      If given id is of type extended identifier,
;*                      then EIDH and EIDL are read too to form 32 bit
;*                      value
;*
;********************************************************************/

CANReadRegFunc
	GLOBAL	CANReadRegFunc
        movf    POSTINC0,W      ;To increment Pointer to point towards
                                ;TxBnSIDL reg.
        btfsc   POSTDEC0,EXIDE  ;Check for Extended Fram
        bra     ReadExtFram     ;Yes Ext Frame, Read it.
                                ;No, Standard Frame
        banksel Reg1
        clrf    Reg1+2          ;Set High Word to 00 for STD message
        clrf    Reg1+3
        movff   POSTINC0,Reg1+1 ;Copy LH byte
        movff   INDF0,Reg1      ;Save LL byte
        movlw   0x05
        rcall   RotateRight32N  ;Rotate right for 5 times
        movlw   0x1f
        andwf   Reg1+3,F        ;Mask EID <31:28>
        bra     CopyIDVal

ReadExtFram
        banksel Reg1
        movff   POSTINC0,Reg1+3 ;Save EID <28:21>
        movff   INDF0,Reg1+2    ;save EID<20:16>
        clrf    Reg1+1
        clrf    Reg1
        movlw   0x03            ;Position EID <28:18>
        rcall   RotateRight32N  ;
        movlw   0xfc            ;Mask EID<17:16>
        andwf   Reg1+2,F
        movlw   0x03            ;Mask all except EID<17:16>
        andwf   POSTINC0,W
        iorwf   Reg1+2,F
        movff   POSTINC0,Reg1+1 ;Save EID<15:8>
        movff   POSTINC0,Reg1   ;Save EID<7:0>

CopyIDVal
        movff   Reg1,POSTINC1   ;Return LL byte
        movff   Reg1+1,POSTINC1 ;Return LH byte
        movff   Reg1+2,POSTINC1 ;Return HL byte (What if EXt?)
        movff   Reg1+3,POSTINC1 ;Return HH byte

        return


;****************************************************************************
;* Function:            RotateRight32N
;*
;*
;* PreCondition:        None
;*
;* Input:               W reg: Value for total rotation required
;*
;*                      Reg1:Reg1+3 - 32-bit value to be converted
;*                      (Reg1= LL, Reg1+1 =LH, Reg1+2 = HL and Reg1+3 = HH
;*                       byte)
;*
;* Output:              32 bit value in Reg1 shifted right by value in W times
;*
;* Side Effects:        Data Bank changed
;*
;* Overview:            It shifts 32-bit value in Reg1 by W times and returns
;*                      result in Reg1
;*
;****************************************************************************

RotateRight32N

        banksel Reg1
RotateRMore:
        bcf     STATUS,C
        btfsc   Reg1,0          ;Pre-read bit 0 to be copied into
        bsf     STATUS,C        ;Bit 31

        rrcf    Reg1+3,F
        rrcf    Reg1+2,F
        rrcf    Reg1+1,F
        rrcf    Reg1,F
        decfsz  WREG,F
        bra     RotateRMore

        return


;****************************************************************************
;* Function:            CANSendMessageFunc
;*
;*
;* PreCondition:        None
;*
;* Input:               Reg1<3:0> 32-bit Message ID
;*                      FSR1: starting address of data buffer
;*                      m_DataLength - Data Length
;*                      m_Flags - CAN_TX_MSG_FLAGS type
;*
;* Output:              W reg = 0, If buffer is Full
;*                      W reg = 1, If successful
;*
;* Side Effects:        Databank changed
;*
;* Overview:            It copies the data in available hardware or software
;*                      buffer. If present data is of higher priority then
;*                      the data in hardware buffer then it aborts
;*                      transmission of lowest priority data in HW buffer and
;*                      copies it to SW buffer and copies present data to HW
;*                      Buffer for immediate transmission
;*
;****************************************************************************

CANSendMessageFunc
	GLOBAL	CANSendMessageFunc
        banksel TxBufSize
        movf    TxBufSize,W
        xorlw   TxBufMaxSize
        bnz     BufEmpty
        retlw   0x00            ;Send Error Code that Buffer is full

BufEmpty:
        clrf    TxFlags         ;Clear Buf set flags

        movlw   0x03
        subwf   TxBufSize,W
        bnc     LoadHWBuf
        goto    LoadSWBuf

LoadHWBuf:

        banksel TXB0CON
        btfsc   TXB0CON,TXREQ,BANKED
        bra     ChkNxtHWBuf1

        movlw   low(TXB0SIDH)
        movwf   FSR0L           ;Save the address of destination register
        movlw   high(TXB0SIDH)
        movwf   FSR0H
        bsf     TxFlags,CANTxBuf0Flag   ;Indicate Buf 0 Set
        bra     CopyBufData


ChkNxtHWBuf1:
        banksel TXB1CON
        btfsc   TXB1CON,TXREQ, BANKED
        bra     ChkNxtHWBuf2
        movlw   low(TXB1SIDH)
        movwf   FSR0L           ;Save the address of destination register
        movlw   high(TXB1SIDH)
        movwf   FSR0H
        bsf     TxFlags,CANTxBuf1Flag   ;Indicate Buf 1 Set
        bra     CopyBufData

ChkNxtHWBuf2:
        banksel TXB2CON
        btfsc   TXB2CON,TXREQ, BANKED
        bra     CopyBufData     ; What ?
        movlw   low(TXB2SIDH)
        movwf   FSR0L           ;Save the address of destination register
        movlw   high(TXB2SIDH)
        movwf   FSR0H
        bsf     TxFlags,CANTxBuf2Flag   ;Indicate Buf 2 set

CopyBufData:
        nop
        SaveFSR0        ;FSR0 contains starting address of Reg to be read
        SaveFSR1        ;FSR1 contains starting address of Data Buffer
        CANSetReg_PREG_DV_IF m_TxFlags  ;Copy ID value in corresponding Regs.
        RestoreFSR0
        RestoreFSR1
        movlw   0x04            ;Point towards TXBnDLC reg.
        movff   m_DataLength,PLUSW0
        btfss   m_Flags1,CAN_TX_RTR_BIT_NO
        bsf     PLUSW0,TXRTR
        incf    WREG            ;Point towards TxBnD0
        addwf   FSR0L,F         ;Add W value into FSR0 to find
        movlw   0x00
        addwfc  FSR0H,F         ;new pointer value in FSR for TxBnD0
        banksel m_DataLength
        movf    m_DataLength,W  ;Data Length Counter to copy all data

CopyNxtTxData:
        movff   POSTINC1,POSTINC0
	MOVLW	0x1
	movwf	WREG
        decfsz  WREG            ;All data copied?
        bra     CopyNxtTxData   ;No, Copy next data

        DisableInt              ;Disable Interrupt occurrence

        banksel TxBufSize
        incf    TxBufSize       ;Indicate new Buffer size

        btfss   TxFlags,CANTxSoftBufFlag
        bra     HWBufAnal

;This section checks for higher priority message in SW buffer than the HW
;buffer. If SW buf contains higher priority message then it Aborts the
;Transmission of lowest priority message in HW buf and Exchanges the data

        call    FindPriorSWBuf  ;Returns Highest Priority buffer number in
                                ;Temp2 and Data in Temp32Data+4

        banksel TXB0CON
        movlw   0x03
        andwf   TXB0CON,W,BANKED
        bnz     ChkBuf1
        CANReadReg CAN_TX_IDB0, Temp32Data+4    ;
        call    Cmp32Bit        ;Check if SW buffer priority is higher than
        bc      HWBufAnal       ;TxBuf0 Priority
        banksel TXB0CON
        bcf     TXB0CON,TXREQ,BANKED    ;If yes, Request Abort

WaitAbort0:
        btfsc   PIR3,TXB0IF     ;If TxBuf0 is transmitting then TxBuf0 Empty?
        bra     TxBuf0Emptied
        btfss   TXB0CON,TXABT,BANKED    ;Message Aborted?
        bra     WaitAbort0
        bra     TxB0Abtd        ;Message was successfully Aborted

TxBuf0Emptied:
        bcf     PIR3,TXB0IF     ;If TxBuf has finished the Transmission of
        bcf     PIE3,TXB0IE     ;current message than decrease buffer size
        banksel TxBufSize
        decf    TxBufSize,F


TxB0Abtd:
        movlw   low(TXB0SIDH)
        movwf   FSR0L
        movlw   high(TXB0SIDH)
        movwf   FSR0H
        call    ExchangeBuffers         ;Xchng highest priority SW Buffer data
        banksel TXB0CON                 ;with Tx Buffer 0 and
        bsf     TXB0CON,TXREQ,BANKED    ;Request Transmission
        bra     HWBufAnal


ChkBuf1:
        banksel TXB1CON
        movlw   0x03
        andwf   TXB1CON,W,BANKED
        bnz     ChkBuf2

        CANReadReg CAN_TX_IDB1, Temp32Data+4    ;
        call    Cmp32Bit        ;Check if SW Buf priority is higher than
        bc      HWBufAnal       ;TxBuf1
        banksel TXB1CON
        bcf     TXB1CON,TXREQ,BANKED    ;If yes, Request Abort


WaitAbort1:
        btfsc   PIR3,TXB1IF     ;TxBuf0 Empty?
        bra     TxBuf1Emptied
        btfss   TXB1CON,TXABT,BANKED    ;Message Aborted?
        bra     WaitAbort1
        bra     TxB1Abtd        ;Message was successfully Aborted

TxBuf1Emptied:
        bcf     PIR3,TXB1IF     ;If TxBuf has finished the Transmission of
        bcf     PIE3,TXB1IE     ;current message than decrease buffer size
        banksel TxBufSize
        decf    TxBufSize,F


TxB1Abtd:
        movlw   low(TXB1SIDH)
        movwf   FSR0L
        movlw   high(TXB1SIDH)
        movwf   FSR0H
        call    ExchangeBuffers         ;Exchange highest priority SW buffer
        banksel TXB1CON                 ;data with Tx Buffer 1 and
        bsf     TXB1CON,TXREQ,BANKED    ;Request Transmission
        bra     HWBufAnal



ChkBuf2:
        banksel TXB2CON
        movlw   0x03
        andwf   TXB2CON,W,BANKED
        bnz     HWBufAnal

        CANReadReg CAN_TX_IDB2, Temp32Data+4    ;, m_TxFlags
        call    Cmp32Bit        ;Check if SW buffer priority is higher than
        bc      HWBufAnal       ;TxBuf2
        banksel TXB2CON
        bcf     TXB2CON,TXREQ,BANKED    ;If yes, Request Abort

WaitAbort2:
        btfsc   PIR3,TXB2IF     ;TxBuf0 Empty?
        bra     TxBuf2Emptied
        btfss   TXB2CON,TXABT,BANKED    ;Message Aborted?
        bra     WaitAbort2
        bra     TxB2Abtd        ;Message was successfully Aborted

TxBuf2Emptied:
        bcf     PIR3,TXB2IF     ;If TxBuf has finished the transmission of
        bcf     PIE3,TXB2IE     ;current message then decrease Buffer Size
        banksel TxBufSize
        decf    TxBufSize,F

TxB2Abtd:
        movlw   low(TXB2SIDH)
        movwf   FSR0L
        movlw   high(TXB2SIDH)
        movwf   FSR0H
        call    ExchangeBuffers         ;Exchange Highest priority SW buf data
        banksel TXB2CON                 ;with TxBuf2 and
        bsf     TXB2CON,TXREQ,BANKED    ;Request Transmission

HWBufAnal:
        rcall   SetHWBufPrior

        EnableInt

        retlw   0x01            ;Return success Code



LoadSWBuf:
        mullw   D'14'           ;Buffer size in bytes
        movf    PRODL,W         ;Get low byte of result in W reg
        addlw   low(TxBuffer)
        movwf   FSR0L           ;Find Starting address of Soft. Buffer
        clrf    FSR0H
        movlw   high(TxBuffer)
        addwfc  FSR0H,F
        bsf     TxFlags,CANTxSoftBufFlag
        bra     CopyBufData


;****************************************************************************
;* Function:            SetHWBufPrior
;*
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;*
;* Output:              It sets the priority of all HW Tx Buffer depending on
;*                      the Message ID in Buffer. Lower the ID value higher
;*                      the priority
;*
;*
;* Side Effects:        Databank changed
;*
;* Overview:            It sets the CAN TX HW Buffer priority depending on the
;*                      CAN ID in buffer.
;*
;*
;****************************************************************************

SetHWBufPrior

        banksel TXB0CON
        movlw   0xfc
        andwf   TXB0CON,F,BANKED        ;Set Priority level 0 for TxBuf-0
        banksel TXB1CON
        andwf   TXB1CON,F,BANKED        ;Set Priority level 0 for TxBuf-1
        banksel TXB2CON
        andwf   TXB2CON,F,BANKED        ;Set Priority level 0 for TxBuf-2

        CANReadReg CAN_TX_IDB0, Temp32Data      ;
        CANReadReg CAN_TX_IDB1, Temp32Data+4    ;
        rcall   Cmp32Bit
        btfsc   STATUS,C
        bra     Buf1HighPrior
        banksel TXB0CON
        incf    TXB0CON,F,BANKED
        bra     NxtCompare1

Buf1HighPrior:
        banksel TXB1CON
        incf    TXB1CON,F,BANKED

NxtCompare1:
        CANReadReg CAN_TX_IDB0, Temp32Data      ;
        CANReadReg CAN_TX_IDB2, Temp32Data+4    ;
        rcall   Cmp32Bit
        btfsc   STATUS,C
        bra     Buf2HighPrior
        banksel TXB0CON
        incf    TXB0CON,F,BANKED
        bra     NxtCompare2

Buf2HighPrior:
        banksel TXB2CON
        incf    TXB2CON,F,BANKED

NxtCompare2:
        CANReadReg CAN_TX_IDB1, Temp32Data      ;
        CANReadReg CAN_TX_IDB2, Temp32Data+4    ;
        rcall   Cmp32Bit
        btfsc   STATUS,C
        bra     Buf2HighPrior1
        banksel TXB1CON
        incf    TXB1CON,F,BANKED
        bra     NxtCompare3

Buf2HighPrior1:
        banksel TXB2CON
        incf    TXB2CON,F,BANKED

NxtCompare3:

        btfss   TxFlags,CANTxBuf0Flag
        bra     SetNxtBuf1
        banksel TXB0CON
        bsf     TXB0CON,TXREQ, BANKED
        bsf     PIE3,TXB0IE     ;Enable TxBuf0 Int.
SetNxtBuf1:
        btfss   TxFlags,CANTxBuf1Flag
        bra     SetNxtBuf2
        banksel TXB1CON
        bsf     TXB1CON,TXREQ, BANKED
        bsf     PIE3,TXB1IE     ;Enable TxBuf0 Int.
SetNxtBuf2:
        btfss   TxFlags,CANTxBuf2Flag
        bra     SetNxtBuf3
        banksel TXB2CON
        bsf     TXB2CON,TXREQ, BANKED
        bsf     PIE3,TXB2IE     ;Enable TxBuf0 Int.
SetNxtBuf3:


        return


;****************************************************************************
;* Function:            Cmp32Bit
;*
;*
;* PreCondition:        None
;*
;* Input:               Temp32Data -  32-bit data 1
;*                      Temp32Data + 4 - 32-bit Data -2
;*
;* Output:              If Data 1 = Data 2 C =1, Z=1
;*                      If Data 1 > Data 2 C =1, Z=0
;*                      If Data 1 < Data 2 C =0, Z=0
;*
;*
;* Side Effects:        Databank changed
;*
;* Overview:            It compares two 32-bit data and sets the Flag
;*                      accordingly.
;*
;*
;****************************************************************************

Cmp32Bit

        banksel Temp32Data
        movf    Temp32Data+4,w
        subwf   Temp32Data,W

        movf    Temp32Data+5,w
        subwfb  Temp32Data+1,W

        movf    Temp32Data+6,w
        subwfb  Temp32Data+2,W

        movf    Temp32Data+7,w
        subwfb  Temp32Data+3,W

        return


;****************************************************************************
;* Function:            FindPriorSWBuf
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              Max. Priority buffer number into Temp2
;*
;* Side Effects:        Databank changed
;*
;* Overview:            It finds highest priority Message Buffer number
;*
;****************************************************************************

FindPriorSWBuf

        clrf    Temp3           ;Clear Buffer Counter
        banksel Temp32Data
        setf    Temp32Data      ;+4     ;Initialize Maximum data to 0
        setf    Temp32Data+1    ;+5
        setf    Temp32Data+2    ;+6
        setf    Temp32Data+3    ;+7

ChkNxtBufID:
        movf    Temp3,W
        mullw   D'14'           ;Buffer size in bytes
        movf    PRODL,W         ;Get result in W
        addlw   low(TxBuffer)
        movwf   FSR0L           ;Find Starting address of Soft. Buffer
        clrf    FSR0H
        movlw   high(TxBuffer)
        addwfc  FSR0H,F
;       CANReadReg_PREG Temp32Data+4, CAN_CONFIG_XTD_MSG
        CANReadReg_PREG Temp32Data+4
        rcall   Cmp32Bit
        bnc     PrsntDataBig
        movff   Temp32Data+4 ,Temp32Data        ;Present Data is
                                                ;bigger so
        movff   Temp32Data+5 ,Temp32Data+1      ;save it for next comparison
        movff   Temp32Data+6 ,Temp32Data+2
        movff   Temp32Data+7 ,Temp32Data+3
        movff   Temp3,Temp2     ;Save software Buffer Number

PrsntDataBig:
        incf    Temp3,F
        movf    Temp3,W
        addlw   0x03
        banksel TxBufSize
        xorwf   TxBufSize,W
        bnz     ChkNxtBufID

        return


;****************************************************************************
;* Function:            ArrangeBuffers
;*
;* PreCondition:        None
;*
;* Input:               FSR0 - Starting address of buffer 1
;*                      Temp2 - SW buffer number to start sorting
;*
;* Output:              It copies buffer n+1 data to buffer n
;*                      It starts with the buffer number passed in Temp2
;*                      and ends at highest buffer
;*
;* Side Effects:        Databank changed
;*
;* Overview:            It arranges the data in Software buffer for next
;*                      transmission.
;*
;****************************************************************************

ArrangeBuffers
;       clrf    Temp2           ;Temp2 contains Buffer start number
                                ;Clear if want to start with Buf 0 to make
                                ;FIFO
XchngNxtBuf:
        movf    Temp2,W
        mullw   D'14'           ;Buffer size in bytes
        movf    PRODL,W         ;Get result in W
        addlw   low(TxBuffer)
        movwf   FSR0L           ;Find Starting address of present Soft. Buffer
        clrf    FSR0H
        movlw   high(TxBuffer)
        addwfc  FSR0H,F

        incf    Temp2,F
        movf    Temp2,W
        addlw   0x03
        banksel TxBufSize
        subwf   TxBufSize,W     ;Check if Max. Buf size has been reached
        bnc     EndXchng        ;Yes, then end exchanging
;       bz      EndXchng

        movf    Temp2,W
        mullw   D'14'           ;Buffer size in bytes
        movf    PRODL,W         ;Get result in W
        addlw   low(TxBuffer)
        movwf   FSR1L           ;Find Starting address of next Soft. Buffer
        clrf    FSR1H
        movlw   high(TxBuffer)
        addwfc  FSR1H,F

        movlw   D'13'
XchngNxtData:
        movff   POSTINC1,POSTINC0
        decfsz  WREG
        bra     XchngNxtData
        bra     XchngNxtBuf

EndXchng:

        return


;****************************************************************************
;* Function:            ExchangeBuffers
;*
;* PreCondition:        None
;*
;* Input:               FSR0 - Starting address of buffer 1
;*                      Temp2 - SW buffer number
;*
;* Output:
;*
;* Side Effects:        None
;*
;* Overview:            It exchanges the data in Buffer pointed by FSR0 and
;*                      Software buffer (number in Temp2).
;*
;****************************************************************************

ExchangeBuffers

        movf    Temp2,W
        mullw   D'14'           ;Buffer size in bytes
        movf    PRODL,W         ;Get result in W
        addlw   low(TxBuffer)
        movwf   FSR1L           ;Find Starting address of Soft. Buffer
        clrf    FSR1H
        movlw   high(TxBuffer)
        addwfc  FSR1H,F

        movlw   D'13'
XchngNxtData1:
        movff   INDF0,Temp1
        movff   INDF1,POSTINC0
        movff   Temp1,POSTINC1
        decfsz  WREG
        bra     XchngNxtData1

        return


;****************************************************************************
;* Function:            CANReadMessageFunc
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              W reg =0, If no data is pending
;*                      W reg= 1, If data is available
;*
;* Side Effects:        None
;*
;* Overview:            It formats the data in Rx Buffer and returns it.
;*                      It stores 32-bit Message ID, Recd. data, Data Length
;*                      and Receiver Status Flags into user supplied memory
;*                      locations.
;*
;*****************************************************************************

CANReadMessageFunc
	GLOBAL CANReadMessageFunc
        SaveFSR0

        banksel m_RxFlags
        clrf    m_RxFlags

        btfss   RXB0CON,RXFUL
        bra     ChkRxBuf1

        movlw   B'11110001'
        andwf   CANCON,F        ;Select WIN bits for buffer 0
        bcf     PIR3,RXB0IF     ;Clear flag indicating new message in Buf 0
        btfss   COMSTAT,RXB0OVFL        ;Check for Buf 0 Overflow
        bra     B0NotOvrFlow
        bsf     m_RxFlags,CAN_RX_OVERFLOW_BIT_NO

B0NotOvrFlow:
        btfsc   RXB0CON ,FILHIT0
        bsf     m_RxFlags,CAN_RX_FILTER_1_BIT_NO
        bra     CopyBuffer

ChkRxBuf1:
        banksel RXB1CON
        btfss   RXB1CON,RXFUL,BANKED
        bra     ReturnRxErrCode ;Return Error code

        movlw   B'11110001'
        andwf   CANCON,F        ;Select WIN bits for buffer 1
        movlw   B'00001010'     ;
        iorwf   CANCON,F        ;
        bcf     PIR3,RXB1IF     ;Clear flag indicating new message in Buf 0

        banksel m_RxFlags
        btfss   COMSTAT,RXB1OVFL        ;Check for Buf 0 Overflow
        bra     B1NotOvrFlow
        bsf     m_RxFlags,CAN_RX_OVERFLOW_BIT_NO

B1NotOvrFlow:
        movlw   CAN_RX_FILTER_BITS
        andwf   RXB0CON,W       ;Because of WIN bits accessing RXB1CON
        iorwf   m_RxFlags       ;Store the Acceptance filter value into
                                ;Rx_Flags
        movlw   0xf8            ;Mask all bits except 3 LSB's
        andwf   RXB0CON,W       ;And with RXB1CON
        sublw   0x02            ;Whether Filter 0 or 1 caused hit
        bz      CopyBuffer      ;No, Then copy buffer data
        bnc     CopyBuffer

        bsf     m_RxFlags,CAN_RX_DBL_BUFFERED_BIT_NO


CopyBuffer:
        movlw   0x0f
        andwf   RXB0DLC,W       ;Depending on the WIN bits actual register
                                ;will be accessed.
        banksel m_DataLength
        movwf   m_DataLength    ;copy Data length value into register

        banksel m_RxFlags
        btfsc   RXB0CON,RXRTRRO ;Check for Remote Frame bit
        bsf     m_RxFlags,CAN_RX_RTR_FRAME_BIT_NO

        btfsc   RXB0SIDL,EXID   ;Check for Remote Frame bit
        bsf     m_RxFlags,CAN_RX_XTD_FRAME_BIT_NO

        movff   FSR0L,TFSR1     ;Transfer data in Temp. reg. for FSR1
        movff   FSR0H,TFSR1+1

        movlw   low(RXB0SIDH)   ;Point towards starting address of ID
        movwf   FSR0L
        movlw   high(RXB0SIDH)
        movwf   FSR0H

        CANReadReg_PREG Temp32Data      ;, CAN_CONFIG_XTD_MSG
        RestoreFSR1             ;Get source data pointer in FSR1

        movlw   low(RXB0D0)     ;Point towards starting address of ID
        movwf   FSR0L
        movlw   high(RXB0D1)
        movwf   FSR0H

        banksel m_DataLength
        movf    m_DataLength,w
CopyNxtRxData:
        movff   POSTINC0,POSTINC1
        decfsz  WREG
        bra     CopyNxtRxData

        bcf     RXB0CON,RXFUL   ;Indicate that buffer is open to receive Msg.

        movlw   B'11110001'
        andwf   CANCON,F        ;Select default WIN bits

        btfss   PIR3,IRXIF      ;Check for any invalid message occurrence on
        bra     NoInvldMsg      ;the CAN bus
        bcf     PIR3,IRXIF
        banksel m_RxFlags       ;Return Invalid message flag bit
        bsf     m_RxFlags,CAN_RX_INVALID_MSG_BIT_NO
NoInvldMsg:

        retlw   0x01            ;Return Success code

ReturnRxErrCode:

        retlw   0x00            ;Return Error Code


;****************************************************************************
;* Function:            CANISR
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              None
;*
;* Side Effects:        None
;*
;* Overview:            If any data is pending for transmission then it will
;*                      copy highest priority data in Empty buffer and
;*                      requests Transmission.
;*
;****************************************************************************

CANISR
        GLOBAL	CANISR
        movlw   B'00011100'     ;If all Tx interrupts are disabled
        andwf   PIR3,W
        bz      EndCANISR       ;then End ISR
        call    SaveWorkRegs
        clrf    TxFlags
        btfss   PIR3,TXB0IF     ;TxBuf0 Empty?
        bra     ChkTxBuf1Int
        bcf     PIR3,TXB0IF
        bcf     PIE3,TXB0IE
        bsf     TxFlags,CANTxBuf0Flag
        call    FindPriorSWBuf  ;Returns Highest Priority buffer number in
                                ;Temp2 and Data in Temp32Data+4
        movlw   low(TXB0SIDH)
        movwf   FSR0L
        movlw   high(TXB0SIDH)
        movwf   FSR0H
        bra     BufSet


ChkTxBuf1Int:
        btfss   PIR3,TXB1IF     ;TxBuf1 Empty?
        bra     ChkTxBuf2Int
        bcf     PIR3,TXB1IF
        bcf     PIE3,TXB1IE
        bsf     TxFlags,CANTxBuf1Flag
        call    FindPriorSWBuf  ;Returns Highest Priority buffer number in
                                ;Temp2 and Data in Temp32Data+4
        movlw   low(TXB1SIDH)
        movwf   FSR0L
        movlw   high(TXB1SIDH)
        movwf   FSR0H
        bra     BufSet


ChkTxBuf2Int:
        btfss   PIR3,TXB2IF     ;TxBuf2 Empty?
        bra     NoBufEmpty
        bcf     PIR3,TXB2IF
        bcf     PIE3,TXB2IE
        bsf     TxFlags,CANTxBuf2Flag
        call    FindPriorSWBuf  ;Returns Highest Priority buffer number in
                                ;Temp2 and Data in Temp32Data+4
        movlw   low(TXB2SIDH)
        movwf   FSR0L
        movlw   high(TXB2SIDH)
        movwf   FSR0H

BufSet:
        movlw   0x03            ;Check whether any data is pending in Buffer
        banksel TxBufSize
        decf    TxBufSize,F
        subwf   TxBufSize,W
        bc      BufPending
        bz      BufPending
        bra     NoBufEmpty

BufPending:
        call    ExchangeBuffers
        rcall   SetHWBufPrior
        call    ArrangeBuffers

NoBufEmpty:
        rcall   RestoreWorkRegs
EndCANISR

        return


;****************************************************************************
;* Function:            SaveWorkRegs
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              None
;*
;* Side Effects:        None
;*
;* Overview:            It saves all GPR registers used by different functions
;*                      in Temp. locations.
;*
;****************************************************************************

SaveWorkRegs

        movff   Temp32Data,ITemp32Data          ;Save Temp32Data
        movff   Temp32Data+1,ITemp32Data+1
        movff   Temp32Data+2,ITemp32Data+2
        movff   Temp32Data+3,ITemp32Data+3
        movff   Temp32Data+4,ITemp32Data+4
        movff   Temp32Data+5,ITemp32Data+5
        movff   Temp32Data+6,ITemp32Data+6
        movff   Temp32Data+7,ITemp32Data+7

        movff   Reg1,IReg1      ;Save Reg1
        movff   Reg1+1,IReg1+1
        movff   Reg1+2,IReg1+2
        movff   Reg1+3,IReg1+3

        movff   m_TxFlags,Im_TxFlags
        movff   TxFlags,ITxFlags
        movff   Temp1,ITemp1    ;Save Temp1
        movff   Temp2,ITemp2    ;Save Temp2
        movff   Temp3,ITemp3    ;Save Temp3

        movff   FSR0L,IFSR0     ;Save FSR 0
        movff   FSR0H,IFSR0+1

        movff   FSR1L,IFSR1     ;Save FSR 1
        movff   FSR1H,IFSR1+1

        return


;****************************************************************************
;* Function:            RestoreWorkRegs
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              None
;*
;* Side Effects:        None
;*
;* Overview:            It saves all GPR registers used by different functions
;*                      in Temp. locations.
;*
;****************************************************************************

RestoreWorkRegs

        movff   ITemp32Data,Temp32Data          ;Restore Temp32Data
        movff   ITemp32Data+1,Temp32Data+1
        movff   ITemp32Data+2,Temp32Data+2
        movff   ITemp32Data+3,Temp32Data+3
        movff   ITemp32Data+4,Temp32Data+4
        movff   ITemp32Data+5,Temp32Data+5
        movff   ITemp32Data+6,Temp32Data+6
        movff   ITemp32Data+7,Temp32Data+7

        movff   IReg1,Reg1      ;Restore Reg1
        movff   IReg1+1,Reg1+1
        movff   IReg1+2,Reg1+2
        movff   IReg1+3,Reg1+3

        movff   ITxFlags,TxFlags
        movff   Im_TxFlags,m_TxFlags
        movff   ITemp1,Temp1    ;Restore Temp1
        movff   ITemp2,Temp2    ;Restore Temp2
        movff   ITemp3,Temp3    ;Restore Temp3

        movff   IFSR0,FSR0L     ;Restore FSR 0
        movff   IFSR0+1,FSR0H

        movff   IFSR1,FSR1L     ;Restore FSR 1
        movff   IFSR1+1,FSR1H

        return


;*****************************************************************************
;* Function:            CANIsTxPassive()
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              C = 1, if CAN transmit module is error passive as
;*                      defined by CAN specifications.
;*                      C = 0, if CAN transmit module is in active state
;* Side Effects:        None
;*
;*****************************************************************************

CANIsTxPassive

        bcf     STATUS,C
        btfsc   COMSTAT,TXBP
        bsf     STATUS,C        ;If Bus is in Tx passive state, set C

        return


;*****************************************************************************
;* Function:            CANIsRxPassive()
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              C = 1, if CAN receive module is error passive as
;*                      defined by CAN specifications.
;*                      C = 0, if CAN receive module is in active state
;* Side Effects:        None
;*
;*****************************************************************************

CANIsRxPassive

        bcf     STATUS,C
        btfsc   COMSTAT,RXBP
        bsf     STATUS,C        ;If Bus is in Rx passive state, set C
    
 	return


;*****************************************************************************
;* Function:            CANIsBusOff()
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              C = 1, if CAN transmit module is in Bus Off state as
;*                      defined by CAN specifications.
;*                      C = 0, if CAN module is not in bus Off state
;* Side Effects:        None
;*
;*****************************************************************************

CANIsBusOff
	GLOBAL 	CANIsBusOff
        bcf     STATUS,C
        btfsc   COMSTAT,TXBO
        bsf     STATUS,C        ;If Bus is in off state, set C

        return


;****************************************************************************
;* Function:            BOOL  CANIsRxReady()
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              C=1, If one of the receive buffer is empty
;*                      C=0, If none of the receive buffer is empty.
;*
;* Side Effects:        Data banks  changed
;*
;****************************************************************************

CANIsRxReady
        GLOBAL	CANIsRxReady
        bcf     STATUS,C
        btfsc   RXB0CON,RXFUL
        bsf     STATUS,C        ;If buffer is empty than set carry to 
                                ;indicate 

        banksel RXB1CON
        btfsc   RXB1CON,RXFUL,BANKED
        bsf     STATUS,C
        
        return


;****************************************************************************
;* Macro:               BOOL CANIsTxReady()
;*
;* PreCondition:        None
;*
;* Input:               None
;*
;* Output:              C=1, If at least one CAN transmit buffer is empty
;*                      C=0, If all CAN transmit buffers are full
;*
;* Side Effects:        Databank changed
;*
;****************************************************************************

CANIsTxReady
	GLOBAL	CANIsTxReady
        banksel TxBufSize
        movf    TxBufSize,W
        sublw   TxBufMaxSize
        bnz     TxReady1
        bcf     STATUS,C        ;       
TxReady1:

        return
	END