/*
File name:	CAN.c

MCP2515 Controller Area Network Interface for Rabbit 3000 processor

Author:		Richard W. Wall
Date:			October 15, 2006

Notes:
	1. Uses serial port B for SPI
   2. I2C master on port d pins, default SCL=PD6, SDA=PD7
   3. CAN interrupt uses expansion IO port channel 2
   4. Port G bit 0 is CAN Rx flag
   5. Port G bit 1 os CAN Tx flag
*/
#define CAN_CS_BIT      		7
#define CAN_RESET_BIT   		3
#define CAN_CS_SEL BitWrPortI(PGDR,&PGDRShadow,0,CAN_CS_BIT) //set CS activate
#define CAN_CS_REL BitWrPortI(PGDR,&PGDRShadow,1,CAN_CS_BIT) //set CS inactivate
#define byte unsigned char

#define CAN_RESET BitWrPortI(PEDR,&PEDRShadow,0,CAN_RESET_BIT)
#define CAN_RUN BitWrPortI(PEDR,&PEDRShadow,1,CAN_RESET_BIT)

#define SPI_SER_B                   // Use Serial Port B
#define SPI_CLOCK_MODE			0x01	// SPI mode (0,0)
#define SPI_CLK_DIVISOR       5		// SPI clock divider 1 will work but
												// it will generate a warning - depends
                                    // upon length of wires

#use "spi.lib"                      // SPI library
#use "i2c_devices.lib"              // I2C Devices lib - calls I2C.lib

#define CAN_SW_RESET_CTRL     0xC0  // Software reset command
#define CAN_READ_CTRL         0x03  // Read command - 1 or more registers
#define CAN_WRITE_CTRL        0x02  // Write command - 1 or more registrers
#define CAN_RD_STATUS_CTRL    0xA0  // FAST Read CAN_Status register
#define CAN_RD_RX_STATUS_CTRL 0xB0  // FAST Read CAN Rx Status register
#define CAN_LD_TX_BUFFER_CTRL 0x40  // FAST  Write message buffer registers
#define CAN_RD_RX_BUFFER_CTRL 0x90  // FAST  Read message buffer registers
#define CAN_RTS_CTRL          0x80  // CAN  Request to send pin control
#define CAN_BIT_MOD_CTRL      0x05  // Bit modify write command
#define CAN_Rd_BUF_CTRL       0x90
#define CAN_Wr_BUF_CTRL       0x40

#define CAN_BFPCTRL_REG       0x0C  // Not used on ECE341 Project board
#define CAN_TXRTSCTRL_REG     0x0D  // Not used on ECE341 Project board - tied to Gnd
#define CAN_STAT_REG          0x0E
#define CAN_CONFIG_REG        0x0F  // Operation mode configuration
#define CAN_TEC_REG           0x1C  // Transmit error count
#define CAN_REC_REG           0x1D  // Receive error count
#define CAN_INTE_REG          0x2B  // Interrupt enable register
#define CAN_INTF_REG          0x2C  // Interrupt flag register
#define CAN_EFLG_REG          0x2D  // Error flag register

#define CAN_CNF_REG           0x28  // Base address of CAN bit timing registers
#define CAN_RXM0_REG          0x20  // Base Address of receive buffer 0 mask registers
#define CAN_RXM1_REG          0x24  // Base Address of receive buffer 1 mask registers
#define CAN_RXF0_REG          0x00  // Base Address of receive buffer filter 0 registers
#define CAN_RXF1_REG          0x04  // Base Address of receive buffer filter 1 registers
#define CAN_RXF2_REG          0x08  // Base Address of receive buffer filter 2 registers
#define CAN_RXF3_REG          0x10  // Base Address of receive buffer filter 3 registers
#define CAN_RXF4_REG          0x14  // Base Address of receive buffer filter 4 registers
#define CAN_RXF5_REG          0x18  // Base Address of receive buffer filter 5 registers
#define CAN_TXB0_REG          0x30  // Base Address of transmit buffer 0 registers
#define CAN_TXB1_REG          0x40  // Base Address of transmit buffer 1 registers
#define CAN_TXB2_REG          0x50  // Base Address of transmit buffer 2 registers
#define CAN_RXB0_REG          0x60  // Base Address of receive buffer 0 registers
#define CAN_RXB1_REG          0x70  // Base Address of receive buffer 1 registers

// CAN Rx Buffer Control bit definitions
#define CAN_RXRTR_BIT         0x08  // Request remote transmit
#define CAN_ACCFLT0_BITS      0x00  // Use Acceptance filter 0
#define CAN_ACCFLT1_BITS      0x01  // Use Acceptance filter 1
#define CAN_ACCFLT2_BITS      0x02  // Use Acceptance filter 2
#define CAN_ACCFLT3_BITS      0x03  // Use Acceptance filter 3
#define CAN_ACCFLT4_BITS      0x04  // Use Acceptance filter 4
#define CAN_ACCFLT5_BITS      0x05  // Use Acceptance filter 5
#define CAN_FLTR_OFF_BITS     0x60  // Receive all messages
#define CAN_FLTR_EXT_BITS     0x40  // Receive only extented ID packets
#define CAN_FLTR_STD_BITS     0x20  // Receive only standard ID packets
#define CAN_FLTR__BITS        0x00  // Receive standard or extended ID packets

// CAN_TXBxCTRL_REG bit definitions
#define CAN_TXP0_BITS         0x00  // Transmit priority zero (lowest)
#define CAN_TXP1_BITS         0x01  // Transmit priority one
#define CAN_TXP2_BITS         0x02  // Transmit priority two
#define CAN_TXP3_BITS         0x03  // Transmit priority three (highest)
#define CAN_TXREQ_BIT         0x08  // Request message transmit
#define CAN_TXERR_BIT         0x10  // Transmit error
#define CAN_MLOA_BIT          0x20  // Message lost arbitration
#define CAN_ABORT_BIT         0x40  // Message aborted

// CAN_INTE_REG bit definitions - clear interrupt flags using bit modify instruction
#define CAN_RX0IE_BIT         0x01  // Rx Buffer 0 interrupt enable
#define CAN_RX1IE_BIT         0x02  // Rx Buffer 0 interrupt enable
#define CAN_TX0IE_BIT         0x04  // Tx 0 buffer empty flag
#define CAN_TX1IE_BIT         0x08  // Tx 1 buffer empty flag
#define CAN_TX2IE_BIT         0x10  // Tx 2 buffer empty flag

// CAN_INTF_REG bit definitions - clear interrupt flags using bit modify instruction
#define CAN_RX0IF_BIT         0x01  // Tx 0 buffer empty flag
#define CAN_RX1IF_BIT         0x02  // Tx 0 buffer empty flag
#define CAN_TX0IF_BIT         0x04  // Tx 0 buffer empty flag
#define CAN_TX1IF_BIT         0x08  // Tx 1 buffer empty flag
#define CAN_TX2IF_BIT         0x10  // Tx 2 buffer empty flag
#define CAN_ERRIF_BIT         0x20  // Error interrupt flag
#define CAN_WAKIF_BIT         0x40  // Error interrupt flag
#define CAN_MERIF_BIT         0x80  // Error interrupt flag

// CAN Load Tx Buffer bit definitions
#define TXB0SIDH					0x00
#define TXB0D0						0x01
#define TXB1SIDH					0x02
#define TXB1D0						0x03
#define TXB2SIDH					0x04
#define TXB2D0						0x05

// Request to send Packet command control bit definitions
#define TxREQ0 					0x01
#define TxREQ1			 			0x02
#define TxREQ2 					0x04

// CAN_CONFIG_REG bit definitions
#define CAN_NORMAL_BITS       0x00  // Set to this mode to send and receive packets
#define CAN_CONFIG_BITS       0x80  // Set to this mode to initialize MCP2515
#define CAN_LOOPBACK_BITS     0x40
#define CAN_SLEEP_BITS        0x20
#define CAN_LISTEN_BITS       0x60
#define CAN_1SHOT_BIT         0x08
#define CAN_ABORT_ALL_BIT     0x10
#define CAN_CLKEN_BIT         0x04  // Clock out enable - not used on ECE 341 board
#define CAN_CLKPRE1_BITS      0x00  // Clock out = Fosc/1 - not used on ECE 341 board
#define CAN_CLKPRE2_BITS      0x01  // Clock out = Fosc/2 - not used on ECE 341 board
#define CAN_CLKPRE4_BITS      0x02  // Clock out = Fosc/4 - not used on ECE 341 board
#define CAN_CLKPRE8_BITS      0x03  // Clock out = Fosc/8 - not used on ECE 341 board

// CAN Status READ results
#define CAN_RX0IF_STATUS_BIT  0x01  // Receiver buffer 0 full status bit
#define CAN_RX1IF_STATUS_BIT  0x02  // Receiver buffer 1 request to send
#define CAN_TX0REQ_STATUS_BIT 0x04  // Receiver buffer 0 request to send
#define CAN_TX0IF_STATUS_BIT  0x08  // Transmit buffer 0 empty status bit
#define CAN_TX1REQ_STATUS_BIT 0x10  // Receiver buffer 1 request to send
#define CAN_TX1IF_STATUS_BIT  0x20  // Transmit buffer 1 empty status bit
#define CAN_TX2REQ_STATUS_BIT 0x40  // Receiver buffer 2 request to send
#define CAN_TX2IF_STATUS_BIT  0x80  // Transmit buffer 2 empty status bit

// CAN Read status bit definitions
#define	CANINTF_RX0IF			0x01	// Rx buffer 0 full interrupt flag
#define	CANINTF_RX1IF			0x02  // Rx buffer 1 full interrupt flag
#define	TXB0CTRL_TXREQ			0x04	// Tx buffer 0 transmit request flag
#define	CANINTF_TX0IF			0x08	// Tx buffer 0 empty interrupt flag
#define	TXB1CTRL_TXREQ			0x10	// Tx buffer 1 transmit request flag
#define	CANINTF_TX1IF			0x20  // Tx buffer 1 empty interrupt flag
#define	TXB2CTRL_TXREQ			0x40	// Tx buffer 2 transmit request flag
#define	CANINTF_TX2IF			0x80	// Tx buffer 2 empty interrupt flag

#define MAX_CAN_PKT_LEN			8		// Maximum CAN message length
#define PACKET_SIZE           20    // CAN packet buffer size

// External Interrupt Expansion

#define IOX_PORT0          	0x76     // I2C Expansion IC 0
#define IOX_PORT1          	0x72     // I2C Expansion IC 1
#define EXT_INTR0          	0x8000   // Flag to signal external interrupt
#define EXT0_VECTOR        	0x00     // Vector address for external interrupt 0
#define EXT_INTR_CFG       	0x11     // External interrupt setup value
#define EXT_INTR_OFF       	0x00     // Disable external interrupts value
#define CAN_int            	0x04     // CAN interrupt channel on IOX_PORT0
#define Exp_intr5          	0x20     // Expansion IO interrupt for BUTT 3
#define Exp_intr6          	0x40     // Expansion IO interrupt for BUTT 2
#define Exp_intr3          	0x08     // Expansion IO interrupt for BUTT 4
#define Exp_intr4          	0x10     // Expansion IO interrupt for BUTT 5
#define Exp_intr2          	0x04     // Expansion IO interrupt for BUTT 5

#define PG0                	0x01     // Use Port G.0 bit for  "CAN Packet Received"
#define PG0bit             	0x00     // Port G.0 bit position
#define PG1                	0x02     // Use Port G.1 bit for  "CAN Packet Sent
#define PG1bit             	0x01     // Port G.1 bit position
#define SETBIT             	0x01     // Set bit control
#define CLEARBIT           	0x00     // Clear bit control

// FUnction Prototypes
void CAN_init(void);											// Initialize RCM3000 and MCP2515
void ReadCAN(int len, int command, char *rx_buf);	// Read a block of data from teh CAN chip
void WriteCAN(int len, char *rx_buf);					// Write a block of data to the CAN chip
int  ReadStatus(void);                             // Read CAN status register
int  ReadRxStatus(void);									// Read Rx status (poll to determine bufffer)
int ReadRxBuffer(char *buffer, char buffer_number);// Read Rx Buffer
void CAN_bit_modify(char can_register, char can_bit, char can_state); // Bit modify-write
void CAN_print_all(void);									// Print all CAN registers
void CAN_print_data(char *packet, char count, char num); // Print Rx message to STDIO

void init_IOX_interrupts(void);		// External interrupts initialize
root interrupt void IOX_isr0(void);	// External interrupts ISR
int IOX_intr_flag;						// Global variable for communications with ISR

void ms_sw_delay(int delay_period);	// Software delay routing

void main(void)
{
char status;						// CAN controller status
char byte_count;					// Number of bytes in received packet
unsigned int packet_count;		// Counts numbe rof packets received
byte packet[PACKET_SIZE];		// Buffer to sending and recein=ving CAN messages

   CAN_init();                // Initialize CAN controller (uses SPI)
   init_IOX_interrupts();     // Initialize system for External INT0 (uses I2C)

   BitWrPortI(PGDDR,&PGDDRShadow, SETBIT, PG0bit);  // Use PG0 for CAN Rx flag
   BitWrPortI(PGDR, &PGDRShadow,CLEARBIT,PG0bit);   // Clear CAN Rx flag

   BitWrPortI(PGDDR,&PGDDRShadow, SETBIT, PG1bit);  // Use PG0 for CAN Rx flag
   BitWrPortI(PGDR, &PGDRShadow,CLEARBIT,PG1bit);   // Clear CAN Rx flag

   status = ReadStatus();              // Read CAN status register - also
   printf("Status %x\n\r",status);

   ReadCAN(1, CAN_STAT_REG, packet);
   printf("CAN_STAT: %x %x %x\n\r", packet[0], packet[1], packet[2]);

// Write Bit setup to CNF registers 125Kbps
   packet[0] = CAN_WRITE_CTRL;
   packet[1] = CAN_CNF_REG;
   packet[2] = 0x03;
   packet[3] = 0x9E;
   packet[4] = 0x03;
   WriteCAN(5, packet);


// Write Rx Mask 0 buffer
   packet[0] = CAN_WRITE_CTRL;
   packet[1] = CAN_RXM0_REG;
   packet[2] = 0x0;
   packet[3] = 0x0;
   packet[4] = 0x0;
   packet[5] = 0x0;
   WriteCAN(6,packet);

// Write Rx Mask 1 buffer
   packet[0] = CAN_WRITE_CTRL;
   packet[1] = CAN_RXM1_REG;
   packet[2] = 0x0;
   packet[3] = 0x0;
   packet[4] = 0x0;
   packet[5] = 0x0;
   WriteCAN(6,packet);

   CAN_print_all();

   packet[0] = CAN_WRITE_CTRL;
   packet[1] = CAN_CONFIG_REG;
   packet[2] = CAN_NORMAL_BITS;
   WriteCAN(3, packet);

   CAN_print_all();
   packet_count = 0;
   while(1)
   {
      costate	// Print out all MCP2515 registers once each 30 seconds
      {
         waitfor(IntervalSec(30));
         CAN_print_all();
      }
      costate	// his costate uses a preemption to set the IOX_intr_flag
      {
         if((IOX_intr_flag & (EXT_INTR0 | CAN_int)) == (EXT_INTR0 | CAN_int))
         {
            printf("\n\rExternal Interrupt: %x\n\r", IOX_intr_flag);
            status = ReadStatus();              // Read CAN status register
            printf("Status = %x\n\r", status);
            if(status & (CAN_RX0IF_STATUS_BIT)) // Look for new Rx Packet
            {
               byte_count = ReadRxBuffer(packet,0);  // Read Rx Buffer 0
               CAN_print_data(packet, byte_count, 0); // packet to STDIO
               // Reset Rx 0 Interrupt flag
               CAN_bit_modify(CAN_INTF_REG, CAN_RX0IF_BIT, FALSE);
            }
            if(status & (CAN_RX1IF_STATUS_BIT))
            {
               byte_count = ReadRxBuffer(packet,1);  // Read Rx Buffer 1
               CAN_print_data(packet, byte_count, 1);   // packet to STDIO
               // Reset Rx 1 Interrupt flag
               CAN_bit_modify(CAN_INTF_REG, CAN_RX1IF_BIT, FALSE);
            }
            // Clear HW CAN Rx flag
            ipset(2);                          // Protect code
            BitWrPortI(PGDR, &PGDRShadow,CLEARBIT,PG0bit);
            ipres();
            CAN_print_all();                 // Dump all registers to STDIO
            status = ReadStatus();              // Read final status
            printf("Status = %x\n\r\n\r", status);
            // Reset CAN SW interrupt flag
            IOX_intr_flag &= ~(EXT_INTR0 | CAN_int);


            // Load response packet
            ipset(2);                          // Protect code
            BitWrPortI(PGDR, &PGDRShadow,SETBIT,PG1bit);
            ipres();
				packet[0] = CAN_LD_TX_BUFFER_CTRL | TXB0SIDH;
         	packet[1] = 0;    // CAN Identifier
         	packet[2] = 0;
         	packet[3] = 0;
         	packet[4] = 0;
         	packet[5] = 8;		// Message length
				packet[6] = (unsigned char) ((packet_count>>8) & 0xFF);
				packet[7] = (unsigned char) (packet_count & 0xFF);
				packet[8] = 0x11;
				packet[9] = 0x22;
				packet[10] = 0x33;
				packet[11] = 0x44;
				packet[12] = 0x55;
				packet[13] = 0x66;
            WriteCAN(14, packet);

				// Send packet
            packet[0] = CAN_RTS_CTRL | TxREQ0;
            WriteCAN(1, packet);

            do
            {
					status = ReadStatus();
            } while((status & (TXB0CTRL_TXREQ | CANINTF_TX0IF))!= CANINTF_TX0IF);

            ipset(2);                          // Protect code
            BitWrPortI(PGDR, &PGDRShadow,CLEARBIT,PG1bit);
            ipres();
            ++packet_count;	// Increment packet counter

         }
      }
   }
}

/* START FUNCTION DESCRIPTION ********************************************
ReadCAN
SYNTAX:        void ReadCAN(int len, int address, char *rx_buf);
KEYWORDS:      CAN, read, data
DESCRIPTION:   Reads a sequence of one or more CAN register
Parameter 1:   Number of bytes to read
Parameter 2:   Address of starting register
parameter 3;   pointer to receive buffer
RETURN VALUE:  none
Notes:         Must use SPI Write-Read.  Bothe Tx and Rx buffer must be
               the size of len + 2.
END DESCRIPTION **********************************************************/
void ReadCAN(int len, int address, char *rx_buf)
{
byte tx_buf[PACKET_SIZE];
   CAN_CS_SEL;                      // Selece CAN IC
   tx_buf[0] = CAN_READ_CTRL;
   tx_buf[1] = address;             // Data must be clocked out by writing dummy data
   SPIWrRd(tx_buf, rx_buf, len+2);
   CAN_CS_REL;                      // De-select CAN IC
}

/* START FUNCTION DESCRIPTION ********************************************
ReadStatus
SYNTAX:        int  ReadStatus(void);
KEYWORDS:      CAN, read, status
DESCRIPTION:   Reads CAN receiver status  1 == Rx buffer 0 id full
                                          0 == Rx buffer 1 is full.
Parameters:    none
RETURN VALUE:  Status, See Figure 12-9 of MCP2515 datasheet for bit descriptions.
Notes:         Must use SPI Write-Read.  Bothe Tx and Rx buffer must be
               the size of 2.
END DESCRIPTION **********************************************************/
int  ReadStatus(void)
{
#define NUM2RD 2
byte tx_buf[NUM2RD], rx_buf[NUM2RD];
int i;
   CAN_CS_SEL;                      // Selece CAN IC
   tx_buf[0]=  CAN_RD_STATUS_CTRL;
   SPIWrRd(tx_buf, rx_buf, NUM2RD);
   CAN_CS_REL;                      // De-select CAN IC
   return rx_buf[1];                   // De-select CAN IC
}

/* START FUNCTION DESCRIPTION ********************************************
ReadRxStatus
SYNTAX:        int  ReadRxStatus(void);
KEYWORDS:      CAN, read, status
DESCRIPTION:   Reads CAN receiver status  1 == Rx buffer 0 id full
                                          0 == Rx buffer 1 is full.
Parameters:    none
RETURN VALUE:  Rx Status, See Figure 12-8 of MCP2515 datasheet for bit descriptions.
Notes:         Must use SPI Write-Read.  Bothe Tx and Rx buffer must be
               the size of 2.
END DESCRIPTION **********************************************************/
int ReadRxStatus(void)
{
#define NUM2RD 2
byte tx_buf[NUM2RD], rx_buf[NUM2RD];
   CAN_CS_SEL;                      // Selece CAN IC
   tx_buf[0]=  CAN_RD_RX_STATUS_CTRL;
   SPIWrRd(tx_buf, rx_buf, NUM2RD);
   CAN_CS_REL;
   return rx_buf[1];                   // De-select CAN IC
}

/* START FUNCTION DESCRIPTION ********************************************
ReadRxBuffer
SYNTAX:        int ReadRxBuffer(char *buffer, char buffer_number);
KEYWORDS:      CAN, read, receive, buffer
DESCRIPTION:   Reads CAN message from specified Rx buffer.
Parameter 1:   Pointer to data buffer
Parameter 2:   buffer number, 0 or 1
RETURN VALUE:  number of bytes in the message
Notes:         Only data is returned.  The message ID and COunr are stripped
               from the buffer data.  The DLC register is the returned value.
END DESCRIPTION **********************************************************/
int ReadRxBuffer(char *buffer, char buffer_number)
{
#define BUFFER_SIZE 14		// This size is computd from ID = 4, DLC = 1, Data = 8
byte tx_buf[BUFFER_SIZE];
int i, len;
   CAN_CS_SEL;                   // Selece CAN IC
   tx_buf[0]=  CAN_RD_RX_BUFFER_CTRL | (buffer_number<<2);
   SPIWrRd(tx_buf, buffer, BUFFER_SIZE);
   CAN_CS_REL;                   // De-select CAN IC
   len = buffer[5] & 0x0f;			// Make sure message length is not over 8
   if(len>MAX_CAN_PKT_LEN)
         len = MAX_CAN_PKT_LEN;
   for(i=0; i<len; i++)          // Shift data to the beginning of the array
      buffer[i] = buffer[i+6];
   return len;                   // return data length
}

/* START FUNCTION DESCRIPTION ********************************************
WriteCAN
SYNTAX:        void WriteCAN(int len, char *buffer);
KEYWORDS:      CAN, write,
DESCRIPTION:   Writes one or more bytes of data to the CAN buffer
Parameter 1:   Number of bytes to write
Parameter 2:   pointer to array of bytes
RETURN VALUE:  none
Notes:         Format of array
               Byte 0:  CAN_WRITE_CTRL
               byte 1:  Address of starting CAN register
               byte 2:  First data byte
               byte n+2: nth data byte
END DESCRIPTION **********************************************************/
void WriteCAN(int len, char *buffer)
{
   CAN_CS_SEL;                      // Selece CAN IC
   SPIWrite(buffer, len);
// ms_sw_delay(1);                  // May be necessary for slow clock ratea
   CAN_CS_REL;                      // De-select CAN IC
}

/* START FUNCTION DESCRIPTION ********************************************
CAN_bit_modify
SYNTAX:        void CAN_bit_modify(char can_register, char can_bit, char can_state);
KEYWORDS:      CAN, write, modify, read-modify-write
DESCRIPTION:   Sets one or more bits in selected MCP2512 registers.
Parameter 1:   Register to modify
Parameter 2:   Bit mask
Parameter 3:   Bit pattern
RETURN VALUE:  none
END DESCRIPTION **********************************************************/
void CAN_bit_modify(char reg, char mask, char pattern)
{
#define NUM2WR4 4
char tx[NUM2WR4];
   CAN_CS_SEL;                      // Selece CAN IC
   tx[0] = CAN_BIT_MOD_CTRL;
   tx[1] = reg;
   tx[2] = mask;
   tx[3] = pattern;
   SPIWrite(tx, NUM2WR4);
// ms_sw_delay(1);                  // May be necessary for slow clock ratea
   CAN_CS_REL;                      // De-selece CAN IC
}

/* START FUNCTION DESCRIPTION ********************************************
ms_sw_delay
SYNTAX:        nodebug void ms_sw_delay(int delay_period);
KEYWORDS:      Millisecond software delay
DESCRIPTION:   Delays the number of milliseconds specified by parameter 1.
               Port G.7 is bit wise toggled.
Parameter 1:   number of milliseconds to delay
RETURN VALUE:  none
END DESCRIPTION **********************************************************/
nodebug void CAN_init(void)
{
#define NUM2WR3 3		// Number of bytes to write to CAN chip
char tx_buf[NUM2WR3];
   BitWrPortI(PGDDR,&PGDDRShadow, 1, CAN_CS_BIT);  // PG.7 output
   BitWrPortI(PGDCR,&PGDCRShadow, 0, CAN_CS_BIT);  // PG.7 output active high
   BitWrPortI(PGFR,&PGFRShadow, 0, CAN_CS_BIT);    // PG.7 output active high

   BitWrPortI(PEFR,&PEFRShadow, 0, CAN_RESET_BIT); // bit 3 = "normal" output
   BitWrPortI(PEDDR,&PEDDRShadow, 1, CAN_RESET_BIT); // PG.7 output

   CAN_CS_REL;                                     // De-select CAN IC
   CAN_RESET;                                      // Assert hrdware reset
   ms_sw_delay(100);											// Arbitrarily long
   CAN_RUN;                                        // Remove HW reset
   ms_sw_delay(100);                               // Arbitrarily long
   SPIinit();                                      // Initialize SPI interface
   tx_buf[0] = CAN_WRITE_CTRL;							// Enable Rx Buffer full to generate interrupt
   tx_buf[1] = CAN_INTE_REG;
   tx_buf[2] = CAN_RX0IE_BIT | CAN_RX1IE_BIT;
   WriteCAN(NUM2WR3, tx_buf);

}

/* START FUNCTION DESCRIPTION ********************************************
CAN_print_data
SYNTAX:        void CAN_print_data(char *packet, char count, char num);
KEYWORDS:      CAN, print, message
DESCRIPTION:   Prints all MCP2510 CAN registers to STDIO window
Parameter 1:	pointer to data array
Parameter 2:	number of bytes in the data packet (numbre to diaplay)
Parameter 3:	Rx Buffer number (0 or 1)
RETURN VALUE:  none
END DESCRIPTION **********************************************************/
nodebug void CAN_print_data(char *packet, char count, char num)
{
int i,j;

   printf("Buffer:%d Count=%d Data:", num, count);
   for(j=0; j<count; j++)
      printf(" %2X",packet[j]);
   printf("\n\r");
}

/* START FUNCTION DESCRIPTION ********************************************
CAN_print_all
SYNTAX:        void CAN_print_all(void);
KEYWORDS:      CAN, print
DESCRIPTION:   Prints all MCP2510 CAN registers to STDIO window
Parameters:    none
RETURN VALUE:  none
END DESCRIPTION **********************************************************/
nodebug void CAN_print_all(void)
{
int i,j;
char buffer[32];
   printf("\n\r            00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\r");
   printf("___________________________________________________________\n\r");

   for(i=0; i<0x80; i+=0x10)
   {
      ReadCAN(16, i, buffer);
      printf("Address %2X ",i);
      for(j=0; j<16; j++)
         printf(" %2X",buffer[j+2]);
      printf("\n\r");
   }
}

/* START FUNCTION DESCRIPTION ********************************************
ms_sw_delay
SYNTAX:        void ms_sw_delay(int delay_period);
KEYWORDS:      delay, software
DESCRIPTION:   millisecond software delay
Parameters:    none
RETURN VALUE:  none
END DESCRIPTION **********************************************************/
nodebug void ms_sw_delay(int delay_period)
{
unsigned int loop_counter;
   while(delay_period--)
   {
      loop_counter = 717;
      while(loop_counter--);
   }
}

/* START FUNCTION DESCRIPTION ********************************************
init_IOX_interrupts
SYNTAX:        void init_IOX_interrupts(void);
KEYWORDS:      ISR, initialize
DESCRIPTION:   Initializes external interrupt 0
Parameters:    none
RETURN VALUE:  none
END DESCRIPTION **********************************************************/
nodebug void init_IOX_interrupts(void)
{
unsigned int io, flag;

   WrPortI(I0CR, &I0CRShadow, EXT_INTR_OFF);
   IOX_intr_flag = 0;                     // Reset all interrupt flags
   WrPortI(PEDDR, &PEDDRShadow, 0x00);    // Set Port E for all interrupt inputs
   flag = PCF8574_IOX_Wr(IOX_PORT0, 0xff); // Make port zero outputs all for read ops
   if(flag)
   {
      printf("IO Expansion write failed!\n\r");
   }
   SetVectExtern3000(EXT0_VECTOR, IOX_isr0);
   WrPortI(I0CR, &I0CRShadow, EXT_INTR_CFG); // Enable Port E High nibble interrupt
                                             // Interrupt is generated on falling edge
                                             // Interrupt priority interrupt level 1
}

/* START FUNCTION DESCRIPTION ********************************************
IOX_isr0
SYNTAX:        nodebug root interrupt void IOX_isr0(void);
KEYWORDS:      ISR, External Interrupts
DESCRIPTION:   This ISR debounces the switches and returns switch state
               with a flag bit indicating that and external interrupt
RETURN VALUE:  none
END DESCRIPTION **********************************************************/
// ============================================================
nodebug root interrupt void IOX_isr0(void)
{
unsigned char ser_io;
   ser_io = PCF8574_IOX_Rd(IOX_PORT0)&(Exp_intr2) ;
   PCF8574_IOX_Wr(IOX_PORT0, 0xff); // Make port zero outputs all for read ops
   if(!(ser_io & CAN_int))
   {
      IOX_intr_flag |= (ser_io | EXT_INTR0 | CAN_int);   // Set EXP-INTR bits
      BitWrPortI(PGDR, &PGDRShadow,SETBIT,PG0bit);
   }
}

// End of Program