/*********************************************************************
 *                 Flowcode CAN Component Code
 *
 * File: PIC_CAN.c
 *
 * (c) 2009 Matrix Multimedia Ltd.
 * http://www.matrixmultimedia.com
 *
 * Software License Agreement
 *
 * The software supplied herewith by Matrix Multimedia Ltd (the
 * “Company”) for its Flowcode graphical programming language is
 * intended and supplied to you, the Company’s customer, for use
 * solely and exclusively on the Company's products. The software
 * is owned by the Company, 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 licence.
 *
 * 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.
 *
 * Changelog:
 *
 *  date  | by | description
 * -------+----+-----------------------------------------------------
 * 240407 | ST | Created
 * 190607 | BR | Externalised
 * 090707 | ST | Amended and incorporated with OCX component
 * 021208 | SK | New #defines for MIAC compatibility
 * 180309 | BR | Changed delays to be WDT compatible
 * 240309 | BR | Moved private functions from AddDefines section
 * 300409 | BR | Fixed macro param probs and added defines for MIAC CS & INT
 * 130509 | BR | Added % definitions to DefinesCode section
 * 090909 | BR | Ported to HiTECH Compiler.
 * 131109 | BR | Fixed #pragma error HITECH problem
 * 280110 | BR | Fixed Macro Parameter Error
 * 240310 | BR | Added internal CAN functionality
 * 230311 | BR | Changed code to work for hitech and boostc without ifdefs
 ********************************************************************/

/*********************************************************************

 Return & parameter types:
   void
   char
   short
   char*

 Pin directions:
   0 = OUTPUT
   2 = INPUT
   3 = BIDIRECTIONAL

**********************************************************************

[Settings]
CLSID={0ACB1934-EB24-4331-BEF4-BADB2DD32F46}
IsAnalogue=0
MultipleAllowed=0
Description=CAN Flowcode Component

**********************************************************************

[Port]
DesiredPort=0
PortMandatory=0
MX_SAMePortAsID=0

[Pins]
Count=0

[PinPort]
# PORTA = 0
# PORTB = 1
# PORTC = 2
# PORTD = 3
# PORTE = 4

[PinDesiredBit]

[PinDirection]
# DIR_INPUT = 2
# DIR_OUTPUT = 0
# DIR_BIDIRECTIONAL = 3

[PinMustUsePort]
# boolean

[MX_SAMePortAsPinX]
# -1 = any pin
# otherwise, the pin number

[PinMustUsePin]
# boolean

[PinValue]
# boolean (0 = off, 1 = on)

**********************************************************************

[MacroNames]
Count=22
1=SPI_Init
2=SPI_SendByte
3=CAN_MaskFromBit
4=CAN_Reset
5=CAN_Write
6=CAN_Read
7=CAN_Config
8=CAN_ReadStatus
9=CAN_ReadRXStatus
10=CAN_BitModify
11=CAN_ReadRX_ID_and_Data
12=Init
13=SendBuffer
14=CheckRx
15=ShowLEDs
16=ReadSwitches
17=GetRxDataCount
18=GetRxData
19=SetTxData
20=SetTxID
21=GetRxIDLo
22=GetRxIDHi

[MacroReturns]
1=void
2=char
3=char
4=void
5=void
6=char
7=void
8=char
9=char
10=void
11=char
12=void
13=void
14=char
15=void
16=char
17=char
18=char
19=void
20=void
21=char
22=char

[MacroIsPrivate]
1=1
2=1
3=1
4=1
5=1
6=1
7=1
8=1
9=1
10=1
11=1
12=0
13=0
14=0
15=0
16=0
17=0
18=0
19=0
20=0
21=0
22=0


[MacroParameters_SPI_Init]
Count=0

[MacroParamTypes_SPI_Init]


[MacroParameters_SPI_SendByte]
Count=1
1=byte

[MacroParamTypes_SPI_SendByte]
1=char

[MacroParameters_CAN_MaskFromBit]
Count=1
1=which_bit

[MacroParamTypes_CAN_MaskFromBit]
1=char

[MacroParameters_CAN_Reset]
Count=0

[MacroParamTypes_CAN_Reset]


[MacroParameters_CAN_Write]
Count=2
1=addr
2=data

[MacroParamTypes_CAN_Write]
1=char
2=char

[MacroParameters_CAN_Read]
Count=1
1=addr

[MacroParamTypes_CAN_Read]
1=char


[MacroParameters_CAN_Config]
Count=1
1=cfg

[MacroParamTypes_CAN_Config]
1=char


[MacroParameters_CAN_ReadStatus]
Count=0

[MacroParamTypes_CAN_ReadStatus]


[MacroParameters_CAN_ReadRXStatus]
Count=0

[MacroParamTypes_CAN_ReadRXStatus]


[MacroParameters_CAN_BitModify]
Count=3
1=addr
2=mask
3=data

[MacroParamTypes_CAN_BitModify]
1=char
2=char
3=char

[MacroParameters_CAN_ReadRX_ID_and_Data]
Count=1
1=buffer

[MacroParamTypes_CAN_ReadRX_ID_and_Data]
1=char

[MacroParameters_Init]
Count=0

[MacroParamTypes_Init]


[MacroParameters_SendBuffer]
Count=1
1=buffer

[MacroParamTypes_SendBuffer]
1=char

[MacroParameters_CheckRx]
Count=1
1=buffer

[MacroParamTypes_CheckRx]
1=char

[MacroParameters_ShowLEDs]
Count=2
1=led1
2=led2

[MacroParamTypes_ShowLEDs]
1=char
2=char

[MacroParameters_ReadSwitches]
Count=0

[MacroParamTypes_ReadSwitches]


[MacroParameters_GetRxDataCount]
Count=1
1=buffer

[MacroParamTypes_GetRxDataCount]
1=char

[MacroParameters_GetRxData]
Count=2
1=buffer
2=index

[MacroParamTypes_GetRxData]
1=char
2=char

[MacroParameters_SetTxData]
Count=10
1=buffer
2=data_cnt
3=d0
4=d1
5=d2
6=d3
7=d4
8=d5
9=d6
10=d7

[MacroParamTypes_SetTxData]
1=char
2=char
3=char
4=char
5=char
6=char
7=char
8=char
9=char
10=char

[MacroParameters_SetTxID]
Count=3
1=buffer
2=hi
3=lo

[MacroParamTypes_SetTxID]
1=char
2=char
3=char

[MacroParameters_GetRxIDLo]
Count=1
1=buffer

[MacroParamTypes_GetRxIDLo]
1=char

[MacroParameters_GetRxIDHi]
Count=1
1=buffer

[MacroParamTypes_GetRxIDHi]
1=char


 ********************************************************************/

/********************************************************************
 * ADDITIONAL CODE
 ********************************************************************/

/*DefinesCode_Start*/

/**** Macro Substitutions ****
%a = Chip Select Pin
%b = Interrupt Pin
%c = Interrupt Pin Mask
%d = Filter 1 Configuration
%e = Filter 2 Configuration
%f = Filter 3 Configuration
%g = Buffer Control
%h = TXRTS Control
%i = Transmit Buffer 0 Messages
%j = Transmit Buffer 1 Messages
%k = Transmit Buffer 2 Messages
%l = Receive Buffer 0 Messages
%m = Receive Buffer 1 Messages
%n = Internal CAN enable
%o = Internal Bit Rate0
%p = Internal Bit Rate1
%q = Internal Bit Rate2
******************************/

//common defines
#define CAN_CHIPSEL  	%a
#define CAN_INTERRUPT  	%b
#define CAN_INT_MASK  	%c
#define CNF1_VAL  		%d
#define CNF2_VAL  		%e
#define CNF3_VAL  		%f
#define BFPCTRL_VAL    	%g
#define TXRTSCTRL_VAL	%h

#define CAN_MAX_TX_BUF	(3)
#define CAN_MAX_RX_BUF	(2)

//One shot mode, CLKOUT enable, CLKOUT prescaler
#define CANCTRL_VAL		0x80
#define MX_CANSTAT_VAL	0x80

//Extended ID Dummy Values
#define TXB0EID8_VAL	0x00
#define TXB0EID0_VAL	0x00
#define TXB1EID8_VAL	0x00
#define TXB1EID0_VAL	0x00
#define TXB2EID8_VAL	0x00
#define TXB2EID0_VAL	0x00
#define RXF0EID8_VAL	0x00
#define RXF0EID0_VAL	0x00
#define RXF1EID8_VAL	0x00
#define RXF1EID0_VAL	0x00
#define RXF2EID8_VAL	0x00
#define RXF2EID0_VAL	0x00
#define RXF3EID8_VAL	0x00
#define RXF3EID0_VAL	0x00
#define RXF4EID8_VAL	0x00
#define RXF4EID0_VAL	0x00
#define RXF5EID8_VAL	0x00
#define RXF5EID0_VAL	0x00
#define RXM0EID8_VAL	0xFF
#define RXM0EID0_VAL	0xFF
#define RXM1EID8_VAL	0xFF
#define RXM1EID0_VAL	0xFF

//CANCTRL
#define REQOP_CONFIG		0x80
#define REQOP_LISTEN		0x60
#define REQOP_LOOPBACK		0x40
#define REQOP_SLEEP			0x20
#define REQOP_NORMAL		0x00


//Transmission messages (TXB0-2):
%i
%j
%k

//Reception (TXB0-1)
%l
%m

#define INTERNAL_CAN_ENABLE	%n

char CAN_MSG_DLC;
char CAN_MSG_DATA[8];
char MsgFlags = 0;

#ifdef CAN_USE_EXID
  char CAN_MSG_ID[4];
#else
  char CAN_MSG_ID[2];
#endif

#if INTERNAL_CAN_ENABLE == 1

	#define USE_INT_CAN
	#define CAN_OP_MODE_BITS 	0xE0

#else

	//////////////////////////////////////////////////////////
	//THESE SHOULD *NOT* BE MODIFIED BY THE USER:
	/////////////////////////////////////////////////////////
	#ifndef MX_SPI
		#error "Chip does not have SPI capability"
	#endif

	#ifdef MX_SPI_B
	  #define MX_CAN_PORT 		portb
	  #define MX_CAN_TRIS 		trisb
	  #define MX_CAN_SDO_TRIS 	trisb
	  #define MX_CAN_CS_PORT 	portb
	  #define MX_CAN_CS_TRIS 	trisb
	  #define MX_CAN_INT_PORT 	portb
	  #define MX_CAN_INT_TRIS 	trisb
	#endif
	#ifdef MX_SPI_C
	  #define MX_CAN_PORT 		portc
	  #define MX_CAN_TRIS 		trisc
	  #define MX_CAN_SDO_TRIS 	trisc
	  #define MX_CAN_CS_PORT 	portc
	  #define MX_CAN_CS_TRIS 	trisc
	  #define MX_CAN_INT_PORT 	portc
	  #define MX_CAN_INT_TRIS 	trisc
	#endif
	#ifdef MX_SPI_BCB
	  #define MX_CAN_PORT 		portb
	  #define MX_CAN_TRIS 		trisb
	  #define MX_CAN_SDO_TRIS 	trisc
	  #define MX_CAN_CS_PORT 	portb
	  #define MX_CAN_CS_TRIS 	trisb
	  #define MX_CAN_INT_PORT 	portb
	  #define MX_CAN_INT_TRIS 	trisb
	#endif
	#ifdef MX_MIAC
	  #undef MX_CAN_CS_PORT
	  #undef MX_CAN_CS_TRIS
	  #undef MX_CAN_INT_PORT
	  #undef MX_CAN_INT_TRIS
	  #undef CAN_CHIPSEL
	  #undef CAN_INTERRUPT
	  #undef CAN_INT_MASK
	  #define MX_CAN_CS_PORT 	portd
	  #define MX_CAN_CS_TRIS 	trisd
	  #define MX_CAN_INT_PORT 	porta
	  #define MX_CAN_INT_TRIS 	trisa
	  #define CAN_CHIPSEL  		7
	  #define CAN_INTERRUPT  	4
	  #define CAN_INT_MASK  	16
	#endif

	#ifndef MX_CAN_PORT
		#error "MX_CAN_PORT has not been assigned"
	#endif


	//This is the interrupt enable register (set to flag on message received - RX0 and RX1 - and on an error)
	//#define CANINTE_VAL		0x23
	//TODO: should we turn interrupts off, like this:
	//#define CANINTE_VAL		0x00
	//TODO: of just turn on RX interrupts, like this:
	#define CANINTE_VAL		0x03

	// **********************************************************************
	// *              MCP2510 Register Definitions                          *
	// **********************************************************************

	//Configuration Registers
	#define MX_CANSTAT			0x0E
	#define CANCTRL				0x0F
	#define BFPCTRL				0x0C
	#define TEC					0x1C
	#define REC					0x1D
	#define CNF3				0x28
	#define CNF2				0x29
	#define CNF1				0x2A
	#define CANINTE				0x2B
	#define CANINTF				0x2C
	#define EFLG				0x2D
	#define TXRTSCTRL			0x0D

	//Receive Filters
	//NOTE: Use "a" for i={0,1,2} and "b" for i={3,4,5}
	#define RXFxaSIDH(i)			((i*4)+0)
	#define RXFxaSIDL(i)			((i*4)+1)
	#define RXFxaEID8(i)			((i*4)+2)
	#define RXFxaEID0(i)			((i*4)+3)
	#define RXFxbSIDH(i)			((i*4)+4)
	#define RXFxbSIDL(i)			((i*4)+5)
	#define RXFxbEID8(i)			((i*4)+6)
	#define RXFxbEID0(i)			((i*4)+7)
	/*
	#define RXF0SIDH			0x00
	#define RXF0SIDL			0x01
	#define RXF0EID8			0x02
	#define RXF0EID0			0x03
	#define RXF1SIDH			0x04
	#define RXF1SIDL			0x05
	#define RXF1EID8			0x06
	#define RXF1EID0			0x07
	#define RXF2SIDH			0x08
	#define RXF2SIDL			0x09
	#define RXF2EID8			0x0A
	#define RXF2EID0			0x0B
	#define RXF3SIDH			0x10
	#define RXF3SIDL			0x11
	#define RXF3EID8			0x12
	#define RXF3EID0			0x13
	#define RXF4SIDH			0x14
	#define RXF4SIDL			0x15
	#define RXF4EID8			0x16
	#define RXF4EID0			0x17
	#define RXF5SIDH			0x18
	#define RXF5SIDL			0x19
	#define RXF5EID8			0x1A
	#define RXF5EID0			0x1B
	*/

	//Receive Masks
	#define RXMxSIDH(i)			((i*4)+0x20)
	#define RXMxSIDL(i)			((i*4)+0x21)
	#define RXMxEID8(i)			((i*4)+0x22)
	#define RXMxEID0(i)			((i*4)+0x23)

	//Tx Buffers
	#define TXBxCTRL(i)			((i*0x10)+0x30)
	#define TXBxSIDH(i)			((i*0x10)+0x31)
	#define TXBxSIDL(i)			((i*0x10)+0x32)
	#define TXBxEID8(i)			((i*0x10)+0x33)
	#define TXBxEID0(i)			((i*0x10)+0x34)
	#define TXBxDLC(i)			((i*0x10)+0x35)
	#define TXBxD0(i)			((i*0x10)+0x36)
	#define TXBxDy(i,j)			((i*0x10)+0x36+j)

	//Rx Buffers
	#define RXBxCTRL(i)			((i*0x10)+0x60)
	#define RXBxSIDH(i)			((i*0x10)+0x61)
	#define RXBxSIDL(i)			((i*0x10)+0x62)
	#define RXBxEID8(i)			((i*0x10)+0x63)
	#define RXBxEID0(i)			((i*0x10)+0x64)
	#define RXBxDLC(i)			((i*0x10)+0x65)
	#define RXBxD0(i)			((i*0x10)+0x66)
	#define RXBxDy(i,j)			((i*0x10)+0x66+j)


	// *******************************************************************
	// *               Bit register masks                                *
	// *******************************************************************

	//TXBnCTRL
	#define MX_TXREQ			0x08
	#define TXP					0x03

	//RXBnCTRL
	#define RXM					0x60
	#define BUKT				0x04

	//CANCTRL
	#define REQOP				0xE0
	#define MX_ABAT				0x10
	#define CLKEN				0x04
	#define CLKPRE				0x03
	#define OSM					0x08             // (ST) new for the 2515

	//MX_CANSTAT
	#define REQOP				0xE0
	#define ICOD				0x0E

	//CANINTE
	#define RX0IE				0x01
	#define RX1IE				0x02
	#define TX0IE				0x04
	//#define TX1IE				0x80
	//#define TX2IE				0x10
	#define MX_ERRIE			0x20
	#define MX_WAKIE			0x40
	#define IVMIE				0x80

	//CANINTF
	#define RX0IF				0x01
	#define RX1IF				0x02
	#define TX0IF				0x04
	//#define TX1IF				0x80
	//#define TX2IF				0x10
	#define MX_ERRIF			0x20
	#define MX_WAKIF			0x40
	#define IVMIF				0x80

	//BFPCTRL
	#define B1BFS				0x20
	#define B0BFS				0x10
	#define B1BFE				0x08
	#define B0BFE				0x04
	#define B1BFM				0x02
	#define B0BFM				0x01

	//CNF1 Masks
	#define SJW					0xC0
	#define BRP					0x3F

	//CNF2 Masks
	#define BTLMODE				0x80
	#define MX_SAM				0x40
	#define PHSEG1				0x38
	#define PRSEG				0x07

	//CNF3 Masks
	#define MX_WAKFIL			0x40
	#define PHSEG2				0x07
	#define SOF					0x80             // (ST) new for the 2515

	//TXRTSCTRL Masks
	#define TXB2RTS				0x04
	#define TXB1RTS				0x02
	#define TXB0RTS				0x01


	// *******************************************************************
	// *                    Bit Timing Configuration                     *
	// *******************************************************************

	//CNF1
	#define SJW_1TQ				0x40
	#define SJW_2TQ				0x80
	#define SJW_3TQ				0x90
	#define SJW_4TQ				0xC0

	//CNF2
	#define BTLMODE_CNF3		0x80
	#define BTLMODE_PH1_IPT		0x00

	#define SMPL_3X				0x40
	#define SMPL_1X				0x00

	#define PHSEG1_8TQ			0x38
	#define PHSEG1_7TQ			0x30
	#define PHSEG1_6TQ			0x28
	#define PHSEG1_5TQ			0x20
	#define PHSEG1_4TQ			0x18
	#define PHSEG1_3TQ			0x10
	#define PHSEG1_2TQ			0x08
	#define PHSEG1_1TQ			0x00

	#define PRSEG_8TQ			0x07
	#define PRSEG_7TQ			0x06
	#define PRSEG_6TQ			0x05
	#define PRSEG_5TQ			0x04
	#define PRSEG_4TQ			0x03
	#define PRSEG_3TQ			0x02
	#define PRSEG_2TQ			0x01
	#define PRSEG_1TQ			0x00

	//CNF3
	#define PHSEG2_8TQ			0x07
	#define PHSEG2_7TQ			0x06
	#define PHSEG2_6TQ			0x05
	#define PHSEG2_5TQ			0x04
	#define PHSEG2_4TQ			0x03
	#define PHSEG2_3TQ			0x02
	#define PHSEG2_2TQ			0x01
	#define PHSEG2_1TQ			0x00

	#define MX_WAKFIL_ENABLED	0x40
	#define MX_WAKFIL_DISABLED	0x00


	// *******************************************************************
	// *                  Control/Configuration Registers                *
	// *******************************************************************

	//CANINTE
	#define RX0IE_ENABLED		0x01
	#define RX0IE_DISABLED		0x00
	#define RX1IE_ENABLED		0x02
	#define RX1IE_DISABLED		0x00
	#define G_RXIE_ENABLED		0x03
	#define G_RXIE_DISABLED		0x00

	#define TX0IE_ENABLED		0x04
	#define TX0IE_DISABLED		0x00
	#define TX1IE_ENABLED		0x08
	#define TX2IE_DISABLED		0x00
	#define TX2IE_ENABLED		0x10
	#define TX2IE_DISABLED		0x00
	#define G_TXIE_ENABLED		0x1C
	#define G_TXIE_DISABLED		0x00

	#define MX_ERRIE_ENABLED	0x20
	#define MX_ERRIE_DISABLED	0x00
	#define MX_WAKIE_ENABLED	0x40
	#define MX_WAKIE_DISABLED	0x00
	#define IVRE_ENABLED		0x80
	#define IVRE_DISABLED		0x00

	//CANINTF
	#define RX0IF_SET			0x01
	#define RX0IF_RESET			0x00
	#define RX1IF_SET			0x02
	#define RX1IF_RESET			0x00
	#define TX0IF_SET			0x04
	#define TX0IF_RESET			0x00
	#define TX1IF_SET			0x08
	#define TX2IF_RESET			0x00
	#define TX2IF_SET			0x10
	#define TX2IF_RESET			0x00
	#define MX_ERRIF_SET		0x20
	#define MX_ERRIF_RESET		0x00
	#define MX_WAKIF_SET		0x40
	#define MX_WAKIF_RESET		0x00
	#define IVRF_SET			0x80
	#define IVRF_RESET			0x00


	#define ABORT				0x10

	#define CLKOUT_ENABLED		0x04
	#define CLKOUT_DISABLED		0x00
	#define CLKOUT_PRE_8		0x03
	#define CLKOUT_PRE_4		0x02
	#define CLKOUT_PRE_2		0x01
	#define CLKOUT_PRE_1		0x00

	//MX_CANSTAT
	#define OPMODE_CONFIG		0x80
	#define OPMODE_LISTEN		0x60
	#define OPMODE_LOOPBACK		0x40
	#define OPMODE_SLEEP		0x20
	#define OPMODE_NORMAL		0x00


	//RXBnCTRL
	#define RXM_RCV_ALL			0x60
	#define RXM_VALID_EXT		0x40
	#define RXM_VALID_STD		0x20
	#define RXM_VALID_ALL		0x00

	#define RXRTR_REMOTE		0x08
	#define RXRTR_NO_REMOTE		0x00

	#define BUKT_ROLLOVER		0x04
	#define BUKT_NO_ROLLOVER	0x00

	#define FILHIT0_FLTR_1		0x01
	#define FILHIT0_FLTR_0		0x00

	#define FILHIT1_FLTR_5		0x05
	#define FILHIT1_FLTR_4		0x04
	#define FILHIT1_FLTR_3		0x03
	#define FILHIT1_FLTR_2		0x02
	#define FILHIT1_FLTR_1		0x01
	#define FILHIT1_FLTR_0		0x00


	//TXBnCTRL
	#define MX_TXREQ_SEND		0x08
	#define MX_TXREQ_ABORT		0x00

	#define TXP_HIGHEST			0x03
	#define TXP_INTER_HIGH		0x02
	#define TXP_INTER_LOW		0x01
	#define TXP_LOWEST			0x00


	// *******************************************************************
	// *                  Register Bit Masks                             *
	// *******************************************************************

	#define DLC_0				0x00
	#define DLC_1				0x01
	#define DLC_2				0x02
	#define DLC_3				0x03
	#define DLC_4				0x04
	#define DLC_5				0x05
	#define DLC_6				0x06
	#define DLC_7				0x07
	#define DLC_8				0x08


	// *******************************************************************
	// *                  CAN SPI commands                               *
	// *******************************************************************

	#define CAN_RESET			0xC0
	#define CAN_READ			0x03
	#define CAN_WRITE			0x02
	#define CAN_RD_STATUS		0xA0
	#define CAN_BIT_MODIFY		0x05

	#define CAN_RTS				0x80
	#define CAN_RTS_TXB0		0x81
	#define CAN_RTS_TXB1		0x82
	//#define CAN_RTS_TXB2		0x83          // (ST) I think this is wrong..so I changed it to this:
	#define CAN_RTS_TXB2		0x84
	//#define CAN_RTS_TXB(i)		(0x80 + (0x01 << i))
	//NOTE: the above line does not work because the RHS of a shift cannot be a variable

	// (ST) I also added these for multiple requests...
	#define CAN_RTS_TXB01		0x83
	#define CAN_RTS_TXB02		0x85
	#define CAN_RTS_TXB12		0x86
	#define CAN_RTS_TXB012		0x87

	#define CAN_RX_STATUS		0xB0

	#define CAN_RD_RXBUF_ID(i)	(0x90 + (i*4))
	#define CAN_RD_RXBUF_DT(i)	(0x92 + (i*4))

	#define CAN_LD_TXBUF_ID(i)	(0x40 + (i*2))
	#define CAN_LD_TXBUF_DT(i)	(0x41 + (i*2))

#endif

// *******************************************************************
// *                  Miscellaneous                                  *
// *******************************************************************


//uncomment this if supporting extended identifiers:
//#define CAN_USE_EXID

char BF_MASK;

/*DefinesCode_End*/

/*InitialisationCode_Start*/
/*InitialisationCode_End*/

/*InterruptCode_Start*/
/*InterruptCode_End*/

/********************************************************************
 * FUNCTIONS
 ********************************************************************/

//internal function implementations
void SPI_Init()
{
/*Macro_SPI_Init_Start*/

#ifndef USE_INT_CAN

	#ifndef MX_SPI
		#error "Chip does not have SPI capability"
	#endif

	//initialise spi
	set_bit(MX_CAN_TRIS,MX_SPI_SDI);
	clear_bit(MX_CAN_SDO_TRIS,MX_SPI_SDO);
	clear_bit(MX_CAN_TRIS,MX_SPI_SCK);
	clear_bit(MX_CAN_CS_TRIS,CAN_CHIPSEL);
	set_bit(MX_CAN_INT_TRIS,CAN_INTERRUPT);

	//disable the CAN chip select line
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	sspstat = 0;
	st_bit(sspstat, CKE);			//SMP = 0, CKE = 1

	#ifdef _BOOSTC
		#ifdef SSPCON							// SPI Low Speed for Initialise
			sspcon = 0;
			st_bit(sspcon, SSPEN);
		#endif
		#ifdef SSPCON1
			sspcon1 = 0;
			st_bit(sspcon1, SSPEN);
		#endif
	#endif

	#ifdef HI_TECH_C
		#ifdef sspcon							// SPI Low Speed for Initialise
			sspcon = 0;
			st_bit(sspcon, SSPEN);
		#endif
		#ifdef sspcon1
			sspcon1 = 0;
			st_bit(sspcon1, SSPEN);
		#endif
	#endif

	//get the mask for the BF bit for later use
	BF_MASK = CAN_MaskFromBit(BF);

#endif

/*Macro_SPI_Init_End*/
}


char SPI_SendByte(char byte)
{
/*Macro_SPI_SendByte_Start*/
	char retval = 0;

#ifndef USE_INT_CAN

	//send the byte
	sspbuf = byte;

	//wait until data has been received (transmit complete)
	while ((sspstat & BF_MASK) == 0);

	//get received byte
	retval = sspbuf;

#endif

	return retval;
/*Macro_SPI_SendByte_End*/
}


char CAN_MaskFromBit(char which_bit)
{
/*Macro_CAN_MaskFromBit_Start*/
	char retVal = 0;
	switch (which_bit)
	{
		case 0:
			retVal = 0x01;
			break;

		case 1:
			retVal = 0x02;
			break;

		case 2:
			retVal = 0x04;
			break;

		case 3:
			retVal = 0x08;
			break;

		case 4:
			retVal = 0x10;
			break;

		case 5:
			retVal = 0x20;
			break;

		case 6:
			retVal = 0x40;
			break;

		case 7:
			retVal = 0x80;
			break;
	}
	return (retVal);
/*Macro_CAN_MaskFromBit_End*/
}


void CAN_Reset()
{
/*Macro_CAN_Reset_Start*/

#ifndef USE_INT_CAN

	//enable SPI
	clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	SPI_SendByte(CAN_RESET);

	//disable SPI
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	//wait for the CAN device to complete its OST
	delay_us(20);

#endif

/*Macro_CAN_Reset_End*/
}


void CAN_Write(char addr, char data)
{
/*Macro_CAN_Write_Start*/

#ifndef USE_INT_CAN

	//enable SPI
	clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	SPI_SendByte(CAN_WRITE);			//send a byte
	SPI_SendByte(addr);					//send the address
	SPI_SendByte(data);					//send the data

	//disable SPI
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

#endif

/*Macro_CAN_Write_End*/
}


char CAN_Read(char addr)
{
/*Macro_CAN_Read_Start*/

	char data;

#ifndef USE_INT_CAN

	//enable SPI
	clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	SPI_SendByte(CAN_READ);				//read a byte
	SPI_SendByte(addr);					//send the address
	data = SPI_SendByte(0x5A);			//send a don't care byte

	//disable SPI
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

#endif

	return (data);

/*Macro_CAN_Read_End*/
}


void CAN_Config(char cfg)
{
/*Macro_CAN_Config_Start*/

#ifndef USE_INT_CAN

	char mode;
	char done = 0;

	while (done == 0)
	{
		CAN_Write(CANCTRL, cfg);

		Wdt_Delay_Ms(1);				//not sure if this is needed

		//read the config mode back
		mode = CAN_Read(MX_CANSTAT);

		//mask off the config bits
		mode = mode & 0xE0;

		if (mode == cfg)
		{
			//it has been set correctly
			done = 1;
		}
	}

	Wdt_Delay_Ms(1);				//not sure if this is needed

#endif

/*Macro_CAN_Config_End*/
}


char CAN_ReadStatus()
{
/*Macro_CAN_ReadStatus_Start*/

	char retval = 0;

#ifndef USE_INT_CAN

	//enable SPI
	clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	SPI_SendByte(CAN_RD_STATUS);		//read the status
	retval = SPI_SendByte(0x5A);		//send a don't care byte

	//disable SPI
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

#endif

	return (retval);

/*Macro_CAN_ReadStatus_End*/
}


char CAN_ReadRXStatus()
{
/*Macro_CAN_ReadRXStatus_Start*/

	char retval = 0;

#ifndef USE_INT_CAN

	//enable SPI
	clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	SPI_SendByte(CAN_RX_STATUS);		//read the status
	retval = SPI_SendByte(0x5A);		//send a don't care byte

	//disable SPI
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

#endif

	return (retval);

/*Macro_CAN_ReadRXStatus_End*/
}


void CAN_BitModify(char addr, char mask, char data)
{
/*Macro_CAN_BitModify_Start*/

#ifndef USE_INT_CAN

	//enable SPI
	clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	SPI_SendByte(CAN_BIT_MODIFY);		//bit modify
	SPI_SendByte(addr);					//send the address
	SPI_SendByte(mask);					//send the mask
	SPI_SendByte(data);					//send the data

	//disable SPI
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

#endif

/*Macro_CAN_BitModify_End*/
}


char CAN_ReadRX_ID_and_Data(char buffer)
{
/*Macro_CAN_ReadRX_ID_and_Data_Start*/

	//populates CAN_MSG_ID[], CAN_MSG_DLC, and CAN_MSG_DATA[], and returns CAN_MSG_DLC
	char idx = 0;

	if (buffer > CAN_MAX_RX_BUF)
	{
		return (0);
	}

	#ifndef USE_INT_CAN

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(CAN_RD_RXBUF_ID(buffer));		//read the RX ID

		CAN_MSG_ID[idx++] = SPI_SendByte(0x5A);		//read back SIDH

		CAN_MSG_ID[idx++] = SPI_SendByte(0x5A);		//read back SIDL

		sspbuf = 0x5A;						//send a don't care byte
		while ((sspstat & BF_MASK) == 0);	//wait until data has been received (transmit complete)
	  #ifdef CAN_USE_EXID
		CAN_MSG_ID[idx++] = sspbuf;			//read back EXID8
	  #endif

		sspbuf = 0x5A;						//send a don't care byte
		while ((sspstat & BF_MASK) == 0);	//wait until data has been received (transmit complete)
	  #ifdef CAN_USE_EXID
		CAN_MSG_ID[idx++] = sspbuf;			//read back EXID0
	  #endif

		CAN_MSG_DLC = SPI_SendByte(0x5A);			//read back DLC

		//now read the data (if there is any)
		if (CAN_MSG_DLC > 0)
		{
			CAN_MSG_DATA[0] = SPI_SendByte(0x5A);		//read back D0

			if (CAN_MSG_DLC > 1)
			{
				CAN_MSG_DATA[1] = SPI_SendByte(0x5A);			//read back D1

				if (CAN_MSG_DLC > 2)
				{
					CAN_MSG_DATA[2] = SPI_SendByte(0x5A);			//read back D2

					if (CAN_MSG_DLC > 3)
					{
						CAN_MSG_DATA[3] = SPI_SendByte(0x5A);			//read back D3

						if (CAN_MSG_DLC > 4)
						{
							CAN_MSG_DATA[4] = SPI_SendByte(0x5A);			//read back D4

							if (CAN_MSG_DLC > 5)
							{
								CAN_MSG_DATA[5] = SPI_SendByte(0x5A);			//read back D5

								if (CAN_MSG_DLC > 6)
								{
									CAN_MSG_DATA[6] = SPI_SendByte(0x5A);			//read back D6

									if (CAN_MSG_DLC > 7)
									{
										CAN_MSG_DATA[7] = SPI_SendByte(0x5A);			//read back D7
									}
								}
							}
						}
					}
				}
			}
		}

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	#endif

	return (CAN_MSG_DLC);
/*Macro_CAN_ReadRX_ID_and_Data_End*/
}


void Init()
{
/*Macro_Init_Start*/

#ifdef USE_INT_CAN

	//configure CAN I/O
	ciocon = 0x30;

    // In order to setup necessary config parameters of CAN module,
    // it must be in CONFIG mode.

    // Request desired mode.
	cancon = REQOP_CONFIG;
	// Wait till desired mode is set.
    while( (canstat & CAN_OP_MODE_BITS) != REQOP_CONFIG );

    // ************************************
    // Now set the baud rate.
    // 20MHz XTAL Required for correct baud
    // ************************************
	brgcon3 = CNF3_VAL;
	brgcon2 = CNF2_VAL;
	brgcon1 = CNF1_VAL;

    rxf0sidh = RXF0SIDH_VAL;    // ID Filter 0 - Buffer 0
	rxf0sidl = RXF0SIDL_VAL;
	rxf0eidh = RXF0EID8_VAL;
	rxf0eidl = RXF0EID0_VAL;
	rxf1sidh = RXF1SIDH_VAL;    // ID Filter 1 - Buffer 0
	rxf1sidl = RXF1SIDL_VAL;
	rxf1eidh = RXF1EID8_VAL;
	rxf1eidl = RXF1EID0_VAL;
	rxf2sidh = RXF2SIDH_VAL;    // ID Filter 2 - Buffer 1
	rxf2sidl = RXF2SIDL_VAL;
	rxf2eidh = RXF2EID8_VAL;
	rxf2eidl = RXF2EID0_VAL;
	rxf3sidh = RXF3SIDH_VAL;    // ID Filter 3 - Buffer 1
	rxf3sidl = RXF3SIDL_VAL;
	rxf3eidh = RXF3EID8_VAL;
	rxf3eidl = RXF3EID0_VAL;
	rxf4sidh = RXF4SIDH_VAL;    // ID Filter 4 - Buffer 1
	rxf4sidl = RXF4SIDL_VAL;
	rxf4eidh = RXF4EID8_VAL;
	rxf4eidl = RXF4EID0_VAL;
	rxf5sidh = RXF5SIDH_VAL;    // ID Filter 5 - Buffer 1
	rxf5sidl = RXF5SIDL_VAL;
	rxf5eidh = RXF5EID8_VAL;
	rxf5eidl = RXF5EID0_VAL;
	rxm0sidh = RXM0SIDH_VAL;    // ID Mask 0   - Buffer 0
	rxm0sidl = RXM0SIDL_VAL;
	rxm0eidh = RXM0EID8_VAL;
	rxm0eidl = RXM0EID0_VAL;
	rxm1sidh = RXM1SIDH_VAL;    // ID Mask 1   - Buffer 1
	rxm1sidl = RXM1SIDL_VAL;
	rxm1eidh = RXM1EID8_VAL;
	rxm1eidl = RXM1EID0_VAL;

	cancon = cancon & 0xE0;
	//cancon = cancon | 0x0C;
	rxb0con = RXB0CTRL_VAL;    	// Receive Buffer 0 Control

	cancon = cancon & 0xE0;
	cancon = cancon | 0x0A;
	rxb0con = RXB1CTRL_VAL;     // Receive Buffer 1 Control

	cancon = cancon & 0xE0;
	cancon = cancon | 0x08;
	rxb0con = TXB0CTRL_VAL;     // Transmit Buffer 0 Control
	rxb0sidh = TXB0SIDH_VAL;    // Transmit ID 0
	rxb0sidl = TXB0SIDL_VAL;
	rxb0eidh = TXB0EID8_VAL;
	rxb0eidl = TXB0EID0_VAL;
	rxb0dlc = TXB0DLC_VAL;
	rxb0d0 = TXB0DB0_VAL;      // Transmit Data Bytes
	rxb0d1 = TXB0DB1_VAL;
	rxb0d2 = TXB0DB2_VAL;
	rxb0d3 = TXB0DB3_VAL;
	rxb0d4 = TXB0DB4_VAL;
	rxb0d5 = TXB0DB5_VAL;
	rxb0d6 = TXB0DB6_VAL;
	rxb0d7 = TXB0DB7_VAL;

	cancon = cancon & 0xE0;
	cancon = cancon | 0x06;
	rxb0con = TXB1CTRL_VAL;     // Transmit Buffer 1 Control
	rxb0sidh = TXB1SIDH_VAL;    // Transmit ID 1
	rxb0sidl = TXB1SIDL_VAL;
	rxb0eidh = TXB1EID8_VAL;
	rxb0eidl = TXB1EID0_VAL;
	rxb0dlc = TXB1DLC_VAL;
	rxb0d1 = TXB1DB0_VAL;      // Transmit Data Bytes
	rxb0d1 = TXB1DB1_VAL;
	rxb0d2 = TXB1DB2_VAL;
	rxb0d3 = TXB1DB3_VAL;
	rxb0d4 = TXB1DB4_VAL;
	rxb0d5 = TXB1DB5_VAL;
	rxb0d6 = TXB1DB6_VAL;
	rxb0d7 = TXB1DB7_VAL;

	cancon = cancon & 0xE0;
	cancon = cancon | 0x04;
	rxb0con = TXB2CTRL_VAL;     // Transmit Buffer 2 Control
	rxb0sidh = TXB2SIDH_VAL;    // Transmit ID 2
	rxb0sidl = TXB2SIDL_VAL;
	rxb0eidh = TXB2EID8_VAL;
	rxb0eidl = TXB2EID0_VAL;
	rxb0dlc = TXB2DLC_VAL;
	rxb0d0 = TXB2DB0_VAL;      // Transmit Data Bytes
	rxb0d1 = TXB2DB1_VAL;
	rxb0d2 = TXB2DB2_VAL;
	rxb0d3 = TXB2DB3_VAL;
	rxb0d4 = TXB2DB4_VAL;
	rxb0d5 = TXB2DB5_VAL;
	rxb0d6 = TXB2DB6_VAL;
	rxb0d7 = TXB2DB7_VAL;

    // Request desired mode.
   	cancon = REQOP_NORMAL;

   	// Wait till desired mode is set.
    while( (canstat & CAN_OP_MODE_BITS) != REQOP_NORMAL );

#else

	//Init SPI
	SPI_Init();

	//brief pause here
	Wdt_Delay_Ms(50);

	//Reset the CAN device
	CAN_Reset();

	//Put the CAN device into config mode
	CAN_Config(REQOP_CONFIG);

	//Initialise all the CAN device registers
	//enable SPI
	clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	SPI_SendByte(CAN_WRITE);        //CAN write mode
	SPI_SendByte(0x00);             //start writting at address 0x00

	SPI_SendByte(RXF0SIDH_VAL);     // RXF0SIDH  0x00
	SPI_SendByte(RXF0SIDL_VAL);     // RXF0SIDL  0x01
	SPI_SendByte(RXF0EID8_VAL);     // RXF0EID8  0x02
	SPI_SendByte(RXF0EID0_VAL);     // RXF0EID0  0x03
	SPI_SendByte(RXF1SIDH_VAL);     // RXF1SIDH  0x04
	SPI_SendByte(RXF1SIDL_VAL);     // RXF1SIDL  0x05
	SPI_SendByte(RXF1EID8_VAL);     // RXF1EID8  0x06
	SPI_SendByte(RXF1EID0_VAL);     // RXF1EID0  0x07
	SPI_SendByte(RXF2SIDH_VAL);     // RXF2SIDH  0x08
	SPI_SendByte(RXF2SIDL_VAL);     // RXF2SIDL  0x09
	SPI_SendByte(RXF2EID8_VAL);     // RXF2EID8  0x0A
	SPI_SendByte(RXF2EID0_VAL);     // RXF2EID0  0x0B
	SPI_SendByte(BFPCTRL_VAL);      // BFPCTRL   0x0C
	SPI_SendByte(TXRTSCTRL_VAL);    // TXRTSCTRL 0x0D
	SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x0E
	SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x0F

	SPI_SendByte(RXF3SIDH_VAL);     // RXF3SIDH  0x10
	SPI_SendByte(RXF3SIDL_VAL);     // RXF3SIDL  0x11
	SPI_SendByte(RXF3EID8_VAL);     // RXF3EID8  0x12
	SPI_SendByte(RXF3EID0_VAL);     // RXF3EID0  0x13
	SPI_SendByte(RXF4SIDH_VAL);     // RXF4SIDH  0x14
	SPI_SendByte(RXF4SIDL_VAL);     // RXF4SIDL  0x15
	SPI_SendByte(RXF4EID8_VAL);     // RXF4EID8  0x16
	SPI_SendByte(RXF4EID0_VAL);     // RXF4EID0  0x17
	SPI_SendByte(RXF5SIDH_VAL);     // RXF5SIDH  0x18
	SPI_SendByte(RXF5SIDL_VAL);     // RXF5SIDL  0x19
	SPI_SendByte(RXF5EID8_VAL);     // RXF5EID8  0x1A
	SPI_SendByte(RXF5EID0_VAL);     // RXF5EID0  0x1B
	SPI_SendByte(0x00);             // TEC       0x1C
	SPI_SendByte(0x00);             // REC       0x1D
	SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x1E
	SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x1F

	SPI_SendByte(RXM0SIDH_VAL);     // RXM0SIDH  0x20
	SPI_SendByte(RXM0SIDL_VAL);     // RXM0SIDL  0x21
	SPI_SendByte(RXM0EID8_VAL);     // RXM0EID8  0x22
	SPI_SendByte(RXM0EID0_VAL);     // RXM0EID0  0x23
	SPI_SendByte(RXM1SIDH_VAL);     // RXM1SIDH  0x20
	SPI_SendByte(RXM1SIDL_VAL);     // RXM1SIDL  0x21
	SPI_SendByte(RXM1EID8_VAL);     // RXM1EID8  0x26
	SPI_SendByte(RXM1EID0_VAL);     // RXM1EID0  0x27
	SPI_SendByte(CNF3_VAL);         // CNF3      0x28
	SPI_SendByte(CNF2_VAL);         // CNF2      0x29
	SPI_SendByte(CNF1_VAL);         // CNF1      0x2A
	SPI_SendByte(CANINTE_VAL);      // CANINTE   0x2B
	SPI_SendByte(0x00);             // CANINTF   0x2C
	SPI_SendByte(0x00);             // EFLG      0x2D
	SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x2E
	SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x2F

	SPI_SendByte(TXB0CTRL_VAL);     // TXB0CTRL  0x30
	SPI_SendByte(TXB0SIDH_VAL);     // TXB0SIDH  0x31
	SPI_SendByte(TXB0SIDL_VAL);     // TXB0SIDL  0x32
	SPI_SendByte(TXB0EID8_VAL);     // TXB0EID8  0x33
	SPI_SendByte(TXB0EID0_VAL);     // TXB0EID0  0x34
	SPI_SendByte(TXB0DLC_VAL);      // TXB0DLC   0x35
	SPI_SendByte(TXB0DB0_VAL);      // TXB0DB0   0x36
	SPI_SendByte(TXB0DB1_VAL);      // TXB0DB1   0x37
	SPI_SendByte(TXB0DB2_VAL);      // TXB0DB2   0x38
	SPI_SendByte(TXB0DB3_VAL);      // TXB0DB3   0x39
	SPI_SendByte(TXB0DB4_VAL);      // TXB0DB4   0x3A
	SPI_SendByte(TXB0DB5_VAL);      // TXB0DB5   0x3B
	SPI_SendByte(TXB0DB6_VAL);      // TXB0DB6   0x3C
	SPI_SendByte(TXB0DB7_VAL);      // TXB0DB7   0x3D
	SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x3E
	SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x3F

	SPI_SendByte(TXB1CTRL_VAL);     // TXB1CTRL  0x40 Highest priority
	SPI_SendByte(TXB1SIDH_VAL);     // TXB1SIDH  0x41
	SPI_SendByte(TXB1SIDL_VAL);     // TXB1SIDL  0x42
	SPI_SendByte(TXB1EID8_VAL);     // TXB1EID8  0x43
	SPI_SendByte(TXB1EID0_VAL);     // TXB1EID0  0x44
	SPI_SendByte(TXB1DLC_VAL);      // TXB1DLC   0x45
	SPI_SendByte(TXB1DB0_VAL);      // TXB1DB0   0x46
	SPI_SendByte(TXB1DB1_VAL);      // TXB1DB1   0x47
	SPI_SendByte(TXB1DB2_VAL);      // TXB1DB2   0x48
	SPI_SendByte(TXB1DB3_VAL);      // TXB1DB3   0x49
	SPI_SendByte(TXB1DB4_VAL);      // TXB1DB4   0x4A
	SPI_SendByte(TXB1DB5_VAL);      // TXB1DB5   0x4B
	SPI_SendByte(TXB1DB6_VAL);      // TXB1DB6   0x4C
	SPI_SendByte(TXB1DB7_VAL);      // TXB1DB7   0x4D
	SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x4E
	SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x4F

	SPI_SendByte(TXB2CTRL_VAL);     // TXB2CTRL  0x50
	SPI_SendByte(TXB2SIDH_VAL);     // TXB2SIDH  0x51
	SPI_SendByte(TXB2SIDL_VAL);     // TXB2SIDL  0x52
	SPI_SendByte(TXB2EID8_VAL);     // TXB2EID8  0x53
	SPI_SendByte(TXB2EID0_VAL);     // TXB2EID0  0x54
	SPI_SendByte(TXB2DLC_VAL);      // TXB2DLC   0x55
	SPI_SendByte(TXB2DB0_VAL);      // TXB2DB0   0x56
	SPI_SendByte(TXB2DB1_VAL);      // TXB2DB1   0x57
	SPI_SendByte(TXB2DB2_VAL);      // TXB2DB2   0x58
	SPI_SendByte(TXB2DB3_VAL);      // TXB2DB3   0x59
	SPI_SendByte(TXB2DB4_VAL);      // TXB2DB4   0x5A
	SPI_SendByte(TXB2DB5_VAL);      // TXB2DB5   0x5B
	SPI_SendByte(TXB2DB6_VAL);      // TXB2DB6   0x5C
	SPI_SendByte(TXB2DB7_VAL);      // TXB2DB7   0x5D
	SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x5E
	SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x5F

	SPI_SendByte(RXB0CTRL_VAL);     // RXB0CTRL  0x60
	SPI_SendByte(0x00);             // RXB0SIDH  0x61
	SPI_SendByte(0x00);             // RXB0SIDL  0x62
	SPI_SendByte(0x00);             // RXB0EID8  0x63
	SPI_SendByte(0x00);             // RXB0EID0  0x64
	SPI_SendByte(0x00);             // RXB0DLC   0x65
	SPI_SendByte(0x00);             // RXB0DB0   0x66
	SPI_SendByte(0x00);             // RXB0DB1   0x67
	SPI_SendByte(0x00);             // RXB0DB2   0x68
	SPI_SendByte(0x00);             // RXB0DB3   0x69
	SPI_SendByte(0x00);             // RXB0DB4   0x6A
	SPI_SendByte(0x00);             // RXB0DB5   0x6B
	SPI_SendByte(0x00);             // RXB0DB6   0x6C
	SPI_SendByte(0x00);             // RXB0DB7   0x6D
	SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x6E
	SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x6F

	SPI_SendByte(RXB1CTRL_VAL);     // RXB1CTRL  0x70
	SPI_SendByte(0x00);             // RXB1SIDH  0x71
	SPI_SendByte(0x00);             // RXB1SIDL  0x72
	SPI_SendByte(0x00);             // RXB1EID8  0x73
	SPI_SendByte(0x00);             // RXB1EID0  0x74
	SPI_SendByte(0x00);             // RXB1DLC   0x75
	SPI_SendByte(0x00);             // RXB1DB0   0x76
	SPI_SendByte(0x00);             // RXB1DB1   0x77
	SPI_SendByte(0x00);             // RXB1DB2   0x78
	SPI_SendByte(0x00);             // RXB1DB3   0x79
	SPI_SendByte(0x00);             // RXB1DB4   0x7A
	SPI_SendByte(0x00);             // RXB1DB5   0x7B
	SPI_SendByte(0x00);             // RXB1DB6   0x7C
	SPI_SendByte(0x00);             // RXB1DB7   0x7D
	SPI_SendByte(MX_CANSTAT_VAL);   // MX_CANSTAT   0x7E
	SPI_SendByte(CANCTRL_VAL);      // CANCTRL   0x7F

	//disable SPI
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	//Put the CAN device into normal mode
	CAN_Config(REQOP_NORMAL);

#endif

/*Macro_Init_End*/
}


void SendBuffer(char buffer)
{
/*Macro_SendBuffer_Start*/

	if (buffer > CAN_MAX_TX_BUF)
	{
	   return;
	}

	#ifdef USE_INT_CAN

		unsigned int timeout = 0xFFFF;

		switch (buffer)
		{
			case 0:
				cancon = cancon & 0xE0;
				cancon = cancon | 0x08;
				st_bit(rxb0con, TXREQ);							//Set Message Transmission Flag
				while (ts_bit(rxb0con, TXREQ) && timeout)		//Wait for message to send
					timeout = timeout - 1;
				break;
			case 1:
				cancon = cancon & 0xE0;
				cancon = cancon | 0x06;
				st_bit(rxb0con, TXREQ);
				while (ts_bit(rxb0con, TXREQ) && timeout)
					timeout = timeout - 1;
				break;
			case 2:
				cancon = cancon & 0xE0;
				cancon = cancon | 0x04;
				st_bit(rxb0con, TXREQ);
				while (ts_bit(rxb0con, TXREQ) && timeout)
					timeout = timeout - 1;
				break;
		}

	#else

		char cmd = CAN_RTS;         //default value

		switch (buffer)
		{
		   case 0:
			   cmd = CAN_RTS_TXB0;
			   break;

		   case 1:
			   cmd = CAN_RTS_TXB1;
			   break;

		   case 2:
			   cmd = CAN_RTS_TXB2;
			   break;
		}
		//NOTE: this following didn't work:
		//cmd = CAN_RTS_TXB(buffer);

		//enable SPI
		clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

		SPI_SendByte(cmd);

		//disable SPI
		set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	#endif

/*Macro_SendBuffer_End*/
}


char CheckRx(char buffer)
{
/*Macro_CheckRx_Start*/

	//returns 1 if the buffer is full, 0 otherwise
	char rx_status;
	char status_mask;
	char retval = 0;

	if (buffer > CAN_MAX_RX_BUF)
	{
	   return (0);
	}

#ifdef USE_INT_CAN

	if (buffer == 0)
	{
		cancon = cancon & 0xE0;
		//cancon = cancon | 0x0C;		//Rx Buffer 0
	}
	else
	{
		cancon = cancon & 0xE0;
		cancon = cancon | 0x0A; 	//Rx Buffer 1
	}

	if (ts_bit(rxb0con, RXFUL))
	{
		CAN_MSG_DLC = rxb0dlc & 0b00001111;	// Retrieve message length.
		CAN_MSG_ID[0] = rxb0sidh;
		CAN_MSG_ID[1] = rxb0sidl;
		if(CAN_MSG_DLC > 0)
		{
			CAN_MSG_DATA[0] = rxb0d0;
			if(CAN_MSG_DLC > 1)
			{
				CAN_MSG_DATA[1] = rxb0d1;
				if(CAN_MSG_DLC > 2)
				{
					CAN_MSG_DATA[2] = rxb0d2;
					if(CAN_MSG_DLC > 3)
					{
						CAN_MSG_DATA[3] = rxb0d3;
						if(CAN_MSG_DLC > 4)
						{
							CAN_MSG_DATA[4] = rxb0d4;
							if(CAN_MSG_DLC > 5)
							{
								CAN_MSG_DATA[5] = rxb0d5;
								if(CAN_MSG_DLC > 6)
								{
									CAN_MSG_DATA[6] = rxb0d6;
									if(CAN_MSG_DLC > 7)
									{
										CAN_MSG_DATA[7] = rxb0d7;
									}
								}
							}
						}
					}
				}
			}
		}
		cr_bit(rxb0con, RXFUL);
	}
	else
		return 0;

	retval = 1;

#else

	if (buffer == 1)
	{
	   //status_mask = 0x02;       //if using CAN_ReadStatus
	   status_mask = 0x80;         //if using CAN_ReadRXStatus
	} else {
	   //status_mask = 0x01;       //if using CAN_ReadStatus
	   status_mask = 0x40;         //if using CAN_ReadRXStatus
	}

	//rx_status = CAN_ReadStatus();    //if using CAN_ReadStatus
	rx_status = CAN_ReadRXStatus();    //if using CAN_ReadRXStatus

	if ((rx_status & status_mask) != 0)
	{
	   retval = 1;

	   //now read in the id and data info
	   CAN_ReadRX_ID_and_Data(buffer);
	}

#endif

	return (retval);
/*Macro_CheckRx_End*/
}


void ShowLEDs(char led1, char led2)
{
/*Macro_ShowLEDs_Start*/

#ifdef USE_INT_CAN

#else

	// Code_CAN_ShowLEDs
	char data = 0;

	if (led1 != 0)
	{
	   data = data | 0x10;
	}
	if (led2 != 0)
	{
	   data = data | 0x20;
	}

	CAN_BitModify(BFPCTRL, 0x30, data);

#endif

/*Macro_ShowLEDs_End*/
}


char ReadSwitches()
{
/*Macro_ReadSwitches_Start*/

	char retval = 0;

#ifdef USE_INT_CAN

#else

	// Code_CAN_ReadSwitches
	retval = CAN_Read(TXRTSCTRL);

	retval = retval & 0x38;         // mask off the state
	retval = retval / 8;            // divide by 8 to leave switch data in bottom 3 bits

#endif

	return (retval);
/*Macro_ReadSwitches_End*/
}


char GetRxDataCount(char buffer)
{
/*Macro_GetRxDataCount_Start*/

	return (CAN_MSG_DLC);

/*Macro_GetRxDataCount_End*/
}


char GetRxData(char buffer, char index)
{
/*Macro_GetRxData_Start*/

	if (index > 7)
	{
	   return (0);
	}
	return (CAN_MSG_DATA[index]);

/*Macro_GetRxData_End*/
}


void SetTxData(char buffer, char data_cnt, char d0, char d1, char d2, char d3, char d4, char d5, char d6, char d7)
{
/*Macro_SetTxData_Start*/

	// Code_CAN_SetTxData
	if (buffer > CAN_MAX_TX_BUF)
	{
	   return;
	}

	if (data_cnt > 8)
	{
	   return;
	}


#ifdef USE_INT_CAN

	switch(buffer)
	{
		case 0:
			cancon = cancon & 0xE0;
			cancon = cancon | 0x08;	//Tx Buffer 0
			break;
		case 1:
			cancon = cancon & 0xE0;
			cancon = cancon | 0x06;	//Tx Buffer 1
			break;
		case 2:
			cancon = cancon & 0xE0;
			cancon = cancon | 0x04;	//Tx Buffer 2
			break;
	}

	rxb0dlc = data_cnt;		// Set data count
	if (data_cnt > 0)
	{
	   rxb0d0 = d0;
	   if (data_cnt > 1)
	   {
		   rxb0d1 = d1;
		   if (data_cnt > 2)
		   {
			   rxb0d2 = d2;
			   if (data_cnt > 3)
			   {
				   rxb0d3 = d3;
				   if (data_cnt > 4)
				   {
					   rxb0d4 = d4;
					   if (data_cnt > 5)
					   {
						   rxb0d5 = d5;
						   if (data_cnt > 6)
						   {
							   rxb0d6 = d6;
							   if (data_cnt > 7)
							   {
								   rxb0d7 = d7;
							   }
						   }
					   }
				   }
			   }
		   }
	   }
	}


#else

	char i;
	char dlc_addr = TXBxDLC(buffer);

	//enable SPI
	clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	SPI_SendByte(CAN_WRITE);        //CAN write mode
	SPI_SendByte(dlc_addr);         //start writting at address 0x00
	SPI_SendByte(data_cnt);         //send the DLC value

	//now fill the data bytes...
	//if (data_cnt > 0)
	//{
	//  for (i=0; i<data_cnt; i++)
	//  {
	//      SPI_SendByte(CAN_TXMSG[i]);
	//  }
	//}

	//now fill the data bytes...
	if (data_cnt > 0)
	{
	   SPI_SendByte(d0);
	   if (data_cnt > 1)
	   {
		   SPI_SendByte(d1);
		   if (data_cnt > 2)
		   {
			   SPI_SendByte(d2);
			   if (data_cnt > 3)
			   {
				   SPI_SendByte(d3);
				   if (data_cnt > 4)
				   {
					   SPI_SendByte(d4);
					   if (data_cnt > 5)
					   {
						   SPI_SendByte(d5);
						   if (data_cnt > 6)
						   {
							   SPI_SendByte(d6);
							   if (data_cnt > 7)
							   {
								   SPI_SendByte(d7);
							   }
						   }
					   }
				   }
			   }
		   }
	   }
	}

	//disable SPI
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

#endif

/*Macro_SetTxData_End*/
}


void SetTxID(char buffer, char hi, char lo)
{
/*Macro_SetTxID_Start*/

	// Code_SetTxID
	if (buffer > CAN_MAX_TX_BUF)
	{
	   return;
	}

#ifdef USE_INT_CAN

	switch(buffer)
	{
		case 0:
			cancon = cancon & 0xE0;
			cancon = cancon | 0x08;
			txb0sidh = hi;		//set the Hi ID value
			txb0sidl = lo;		//set the Lo ID value
			break;
		case 1:
			cancon = cancon & 0xE0;
			cancon = cancon | 0x06;
			txb1sidh = hi;		//set the Hi ID value
			txb1sidl = lo;		//set the Lo ID value
			break;
		case 2:
			cancon = cancon & 0xE0;
			cancon = cancon | 0x04;
			txb2sidh = hi;		//set the Hi ID value
			txb2sidl = lo;		//set the Lo ID value
			break;
	}

#else

	char i;
	char id_addr = TXBxSIDH(buffer);

	//enable SPI
	clear_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

	SPI_SendByte(CAN_WRITE);        //CAN write mode
	SPI_SendByte(id_addr);          //start writting at hi id address
	SPI_SendByte(hi);               //send the Hi ID value
	SPI_SendByte(lo);               //send the Lo ID value

	//disable SPI
	set_bit(MX_CAN_CS_PORT, CAN_CHIPSEL);

#endif

/*Macro_SetTxID_End*/
}


char GetRxIDLo(char buffer)
{
/*Macro_GetRxIDLo_Start*/

	return (CAN_MSG_ID[1]);

/*Macro_GetRxIDLo_End*/
}


char GetRxIDHi(char buffer)
{
/*Macro_GetRxIDHi_Start*/

	return (CAN_MSG_ID[0]);

/*Macro_GetRxIDHi_End*/
}


