/////////////////////////////////////////////////////////////////////////
////                        can-18F4580.c                             ////
//// CAN Library routines for Microchip's PIC18Cxx8 and 18Fxx8 line  ////
////                                                                 ////
//// This library provides the following functions:                  ////
////  (for more information on these functions see the comment       ////
////   header above each function)                                   ////
////                                                                 ////
////    can_init - Configures the PIC18F4580 CAN peripheral*         ////
////                                                                 ////
////    can_set_baud - Sets the baud rate control registers*         ////
////                                                                 ////
////    can_set_mode - Sets the CAN module into a specific mode*     ////
////																						////
////	  can_set_functional_mode - Sets the function mode					////
////                                                                 ////
////    can_set_id - Sets the standard and extended ID*              ////
////																						////
////	  can_set_extended_id - Sets only extended ID						////
////																						////
////	  can_set_standard_id - Sets only standard ID						////
////                                                                 ////
////    can_get_id - Gets the standard and extended ID*              ////
////	  																					////
////	  can_get_extended_id - Gets only extended ID						////
////																						////
////	  can_get_standard_id - Gets only standard ID						////
////                                                                 ////
////    can_putd - Sends a message/request with specified ID*        ////
////                                                                 ////
////    can_getd - Returns specifid message/request and ID*          ////
////                                                                 ////
////    can_kbhit - Returns true if there is data in one of the*     ////
////                receive buffers                                  ////
////                                                                 ////
////    can_tbe - Returns true if the transmit buffer is ready to    ////
////              send more data*                                    ////
////                                                                 ////
////    can_abort - Aborts all pending transmissions*                ////
////                                                                 ////
////    can_enable_b_transfer - enables buffer as transmitter			////
////																						////
////	  can_enable_b_receiver - enables buffer as receiver 				////
////																						////
////	  can_enable_rtr - enables transmit buffer as Auto-rtr			////
////																						////
////	  can_disable_rtr - disables transmit buffer as Auto-rtr			////
////																						////
////    can_load_rtr - loads an Auto-rtr buffer with data				////
////																						////
////    can_enable_filter - enables one of 15 filters						////
////																						////
////    can_disable_filter - disables one of the 15 filters				////
////																						////
////    can_associate_filter_to_buffer - associates a filter with 	////
////									           a receive buffer				////
////																						////
////	  can_associate_filter_to_mask - associates a filter with a		////
////												mask									////
////																						////
////	  can_fifo_getd - retrive data in FIFO mode (2)						////
////																						////
////	  can_t0_putd																	////
////	  can_t1_putd																	////
////	  can_t2_putd																	////
////	  can_b0_putd																	////
////	  can_b1_putd																	////
////	  can_b2_putd																	////
////	  can_b3_putd																	////
////	  can_b4_putd																	////
////	  can_b5_putd																	////
////	  can_b6_putd																	////
////	  can_b7_putd - place data in a specific buffer						////
////																						////
//// PIN_B3 is CANRX, and PIN_B2 is CANTX.  You will need a CAN      ////
//// transeiver to connect these pins to CANH and CANL bus lines.    ////
////                                                                 ////
//// CCS provides an example, ex_can.c, which shows how to use this  ////
//// library.                                                        ////
////																						////
//// * Designates functions that work in legacy mode                 ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////                                                                 ////
//// Version History                                                 ////
////                                                                 ////
////  Jul 27 04 - can_init() uses CAN_USE_EXTENDED_ID instead of     ////
////              setting all RX filters to extended.                ////
////                                                                 ////
////  Feb 24 04 - can_get_id() fixed for EID<18:20>.                 ////
////                                                                 ////
/////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2003 Custom Computer Services         ////
//// This source code may only be used by licensed users of the CCS  ////
//// C compiler.  This source code may only be distributed to other  ////
//// licensed users of the CCS C compiler.  No other use,            ////
//// reproduction or distribution is permitted without written       ////
//// permission.  Derivative programs created using this software    ////
//// in object code form are not restricted in any way.              ////
/////////////////////////////////////////////////////////////////////////

#include <can-18F4580.h>
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)


#if CAN_DO_DEBUG
 #define can_debug printf
#else
 #define can_debug
#endif


//macros
#define can_kbhit() (RXB0CON.rxful || RXB1CON.rxful || B0CONR.rxful || B1CONR.rxful || B2CONR.rxful || B3CONR.rxful || B4CONR.rxful || B5CONR.rxful)
#define can_tbe() (!TXB0CON.txreq || !TXB1CON.txreq || !TXB2CON.txreq || !B0CONT.txreq || !B1CONT.txreq || !B2CONT.txreq || !B3CONT.txreq || !B4CONT.txreq || !B5CONT.txreq)
#define can_abort()                 (CANCON.abat=1)

// current mode variable
// used by many of the device drivers to prevent damage from the mode
//
int curmode;
int curfunmode;

////////////////////////////////////////////////////////////////////////
//
// can_init()
//
// Initializes PIC18xxx8 CAN peripheral.  Sets the RX filter and masks so the
// CAN peripheral will receive all incoming IDs.  Configures both RX buffers
// to only accept valid valid messages (as opposed to all messages, or all
// extended message, or all standard messages).  Also sets the tri-state
// setting of B2 to output, and B3 to input (apparently the CAN peripheral
// doesn't keep track of this)
//
// The constants (CAN_USE_RX_DOUBLE_BUFFER, CAN_ENABLE_DRIVE_HIGH,
// CAN_ENABLE_CAN_CAPTURE) are given a default define in the can-18xxx8.h file.
// These default values can be overwritten in the main code, but most
// applications will be fine with these defaults.
//
//////////////////////////////////////////////////////////////////////////////
void can_init(void) {
   can_set_mode(CAN_OP_CONFIG);   //must be in config mode before params can be set
   can_set_baud();
	curfunmode=0;

	// RXB0CON
	// 	filthit0=0
	// 	jtoff=0
	//		rxb0dben=1	buffer zero will overflow into buffer one
	//		rxrtrro=0
	//		rxm1:0=0		will recive all valid IDs
   RXB0CON=0;
   RXB0CON.rxm=CAN_RX_VALID;
   RXB0CON.rxb0dben=CAN_USE_RX_DOUBLE_BUFFER;
   RXB1CON=RXB0CON;

   CIOCON.endrhi=CAN_ENABLE_DRIVE_HIGH;
   CIOCON.cancap=CAN_ENABLE_CAN_CAPTURE;

   can_set_id(RX0MASK, CAN_MASK_ACCEPT_ALL, CAN_USE_EXTENDED_ID);  //set mask 0
   can_set_id(RXFILTER0, 0, CAN_USE_EXTENDED_ID);  //set filter 0 of mask 0
   can_set_id(RXFILTER1, 0, CAN_USE_EXTENDED_ID);  //set filter 1 of mask 0

   can_set_id(RX1MASK, CAN_MASK_ACCEPT_ALL, CAN_USE_EXTENDED_ID);  //set mask 1
   can_set_id(RXFILTER2, 0, CAN_USE_EXTENDED_ID);  //set filter 0 of mask 1
   can_set_id(RXFILTER3, 0, CAN_USE_EXTENDED_ID);  //set filter 1 of mask 1
   can_set_id(RXFILTER4, 0, CAN_USE_EXTENDED_ID);  //set filter 2 of mask 1
   can_set_id(RXFILTER5, 0, CAN_USE_EXTENDED_ID);  //set filter 3 of mask 1

	// set dynamic filters
	can_set_id(RXFILTER6, 0, CAN_USE_EXTENDED_ID);
	can_set_id(RXFILTER7, 0, CAN_USE_EXTENDED_ID);
	can_set_id(RXFILTER8, 0, CAN_USE_EXTENDED_ID);
	can_set_id(RXFILTER9, 0, CAN_USE_EXTENDED_ID);
	can_set_id(RXFILTER10, 0, CAN_USE_EXTENDED_ID);
	can_set_id(RXFILTER11, 0, CAN_USE_EXTENDED_ID);
	can_set_id(RXFILTER12, 0, CAN_USE_EXTENDED_ID);
	can_set_id(RXFILTER13, 0, CAN_USE_EXTENDED_ID);
	can_set_id(RXFILTER14, 0, CAN_USE_EXTENDED_ID);
	can_set_id(RXFILTER15, 0, CAN_USE_EXTENDED_ID);

   set_tris_b((*0xF93 & 0xFB ) | 0x08);   //b3 is out, b2 is in

   can_set_mode(CAN_OP_NORMAL);
}

////////////////////////////////////////////////////////////////////////
//
// can_set_baud()
//
// Configures the baud rate control registers.  All the defines here
// are defaulted in the can-18xxx8.h file.  These defaults can, and
// probably should, be overwritten in the main code.
//
// Current defaults are set to work with Microchip's MCP250xxx CAN
// Developers Kit if this PIC is running at 20Mhz.
//
//	BRGCON1 contains the prescaler bits and the Synchronization jump
// 		  width time bits.
//
//			  the prescale values are
//				  111111=(2*64)/clock=Tq
//				  111110=(2*63)/clock=Tq
//					 continued
//				  000001=(2*2)/clock=Tq
//			  	  000000=(2*1)/clock=Tq
//
//			  in the case of can-18xxx8.h, the prescale bits are set to
//			  000100=10/clock profided that the user does not define it
//			  differently
//
//		     The Synchronized Jump Width Bits are
//				  11=4*Tq
//				  10=3*Tq
//				  01=2*Tq
//       	  00=1*Tq
//
//			  in the case of can-18xxx8.h, the SJW bits are set to 0 or 1*Tq
//
//	BRGCON2 contains the Phase Segment 2 Time Select bit, the SAMple bit
//  		  the Phase Segment 1 bits, and the Propagation Time Select bits
//
//			  SEG2PHTS
//			  	  1=Freely Programmable
//				  0=Maximum of PHEG1 or IPT, which ever is greatest
//
//			  in the case of can-18xxx8.h, the SEG2PHTS bit is set to 1 for
//			  freely programmable
//
//			  SAM
//				  1=Three Samples
//				  0=One Sample
//
//			  in the case of can-18xxx8.h, the SAM bit is set to 0 for
//			  one sample
//
//			  SEG1PH2:SEG1PH0
//				  Phase Segment 1 = (SEG1PH2:SEG1PH0+1)*Tq
//
//			  in the case of can-18xxx8.h, the SEG1PH2:SEG1PH0 bits are set to 5
//         for 6*Tq Phase Segment 1 Time
//
//			  PRSEG2:PRSEG0
//			     Propogation Time = (PRSEG2:PRSEG0+1)*TQ
//
//			  in the case of can-18xxx8.h, the PRSEG2:PRSEG0 bits are set to 2
//			  for 3*Tq Propogation Time
//
// BRGCON3 contains the WAKFIL bit and the Phase Segment 2 Time Select bits
//
//			  WAKEFIL
//            1=CAN bus line filter is used for wake-up
//				  0=CAN bus line filter is not used for wake-up
//
//			  in the case of can-18xx8.h, the WAKEFIL bit is set to 0 for
//			  CAN bus not used for wake-up
//
//			  SEG2PH2:SEG2PH0
//				  Phase Segment 2 Time = (SEG2PH2:SEG2PH0+1)*Tq
//
//			  in the case of can-18xxx8.h, SEG2PH2:SEG3PH0 is set to 5 for
//         6*Tq Phase Segment 2 Time
//
// More information can be found in the PIC18F4580 datasheet section 23.9
////////////////////////////////////////////////////////////////////////
void can_set_baud(void) {
   BRGCON1.brp=CAN_BRG_PRESCALAR;
   BRGCON1.sjw=CAN_BRG_SYNCH_JUMP_WIDTH;

   BRGCON2.prseg=CAN_BRG_PROPAGATION_TIME;
   BRGCON2.seg1ph=CAN_BRG_PHASE_SEGMENT_1;
   BRGCON2.sam=CAN_BRG_SAM;
   BRGCON2.seg2phts=CAN_BRG_SEG_2_PHASE_TS;

   BRGCON3.seg2ph=CAN_BRG_PHASE_SEGMENT_2;
   BRGCON3.wakfil=CAN_BRG_WAKE_FILTER;
}


////////////////////////////////////////////////////////////////////////
//
// can_set_mode
//
// This function first sets three most significant bits (reqop2:reqop0)
// to the mode given through the argument.  The modes can be
//
// mode
//
// 1xx  -> Configuration Mode
//			 	This mode allows the user to configure the Control Registers,
//				the Acceptance Mask Registers and the Acceptance Filter
//				Registers.
//
// 011  -> Listen Only Mode
//				This mode allows the PIC microcontroller to listen to the
//				bus but not actually write to it.
//
// 010  -> Loop Back Mode
//				This mode allows to the transmission of data directly from
//				the Transmission Buffers to the Recive Buffers without
//				actually driving any data to the bus
//
// 001  -> Dissable Mode
//				This mode prefents the PIC microcontroller from transmitting
//				and reciving, however the WAKIF interrupt is still active
//
// 000  -> Normal Mode
//				This is the normal mode of opperation for the CAN bus.  It
//				will recive all messages and is the only mode in which
//				data can be transmitted.
//
//	The reqop bits do not immediatly change the mode of operation, the
// three most significant bits in the CANSTAT register (opmode2:opmode0)
// must change to reflect the actuall change in mode, therefore a while
// statement is used to check if the CANSTAT opmode bits have changed to
// reflect the passed in mode
//
// More information can be found in the PIC18F4580 datasheet section 23.3
////////////////////////////////////////////////////////////////////////
void can_set_mode(CAN_OP_MODE mode) {
   CANCON.reqop=mode;
   while( (CANSTAT.opmode) != mode );
}

////////////////////////////////////////////////////////////////////////
//
// can_set_functional_mode
//
// This function sets the functional mode of the PIC18F4580 ECAN modual
//
//	mode
//
// 00	 -> mode 0 or Legacy Mode.  The processor defaults to this mode
//				on reset in order to maintain backwards compatibility will
//				the previouse PIC18Cxx8 and PIC18Fxx8 CAN moduals.  All code
//				written for the listed microcontrollers will work on the
//				PIC18F4580 will no alterations.
//
//				This mode provides the exact same registers as the previouse
//				moduals.  These include
//
//				3 Transmit Buffers: TXB0, TXB1, TXB2
//				2 Recive Buffers: RXB0, RXB1
//				2 Acceptance Masks: RXM0, RXM1
//				6 Acceptance Filters: RXF0, RXF1, RXF2, RXF3, RXF4, RXF5
//
// 01  -> mode 1 or Enhanced Legacy Mode. This mode is the same as mode
//				0 with the exception that there are more resources available
//				to the CAN modual.  These include
//
//				3  Transmit Buffers: TXB0, TXB1, TXB2
//				2  Recive Buffers: RXB0, RXB1
//				6  Programmable Buffers: B0, B1, B2, B3, B4, B5
//				   Automatic RTR Handling on: B0, B1, B2, B3, B4, B5
//				16 Dynamically assigned acceptance filters: RXF0-RXF15
//				2  Dedicated mask registers,RXM0: RXM1
//				1  Programmable mask register: RXF15
//					Programmable data filter on standard identifier messages: SDFLC
//
// 10	 -> mode 2 or Enhanced FIFO Mode.  This mode produces a first in
//				first out (FIFO) CAN data buffer.  This buffer can be from 2 too
//				8 bytes in length depending on which B buffers are used as recive
//				buffers and which are used as transmit buffers.  The first transmit
//				buffer defines the size, therefor if B4 was the first transmit
//				buffer, RXB0, BXB1, B0, B1, B2, and B3 would form the FIFO buffer
//				for a size of 6 bytes.  If B0 through B5 are all set to recive data,
//				the size will be 8 bytes.  If B0 is set to transmit, the size will
//				be 2 bytes.  The available resources include
//
//				3  Transmit Buffers: TXB0, TXB1, TXB2
//				2  Recive Buffers: RXB0, RXB1
//				6  Programmable Buffers: B0, B1, B2, B3, B4, B5
//				   Automatic RTR Handling on: B0, B1, B2, B3, B4, B5
//				16 Acceptance Filters: RXF0-RXF15
//				2  Dedicated Mask Registers: RXM0, RXM1
//				1  Programmable mask register: RXF15
//					Programmable data filter on standard identifier messages: SDFLC
//
//	More information can be found in the PIC18F4580 datasheet section 23.4
////////////////////////////////////////////////////////////////////////////////
void can_set_functional_mode(CAN_FUN_OP_MODE mode)
{
	can_set_mode(CAN_OP_CONFIG);   //must be in config mode before params can be set
	ECANCON.mdsel=mode;
	curfunmode=mode;
	can_set_mode(CAN_OP_NORMAL);
}

////////////////////////////////////////////////////////////////////////
//
// can_set_id()
//
// Configures the xxxxEIDL, xxxxEIDH, xxxxSIDL and xxxxSIDH registers to
// configure the defined buffer to use the specified ID
//
//   Paramaters:
//     addr - pointer to first byte of ID register, starting with xxxxEIDL.
//            For example, a pointer to RXM1EIDL
//
//     id - ID to set buffer to
//     ext - Set to TRUE if this buffer uses an extended ID, FALSE if not
//
////////////////////////////////////////////////////////////////////////
void can_set_id(int* addr, int32 id, int1 ext) {
   //int *ptr;

   //ptr=addr;

   if (ext) {  //extended
      //eidl
      *addr=make8(id,0); //0:7

      //eidh
      addr--;
      *addr=make8(id,1); //8:15

      //sidl
      addr--;
      *addr=make8(id,2) & 0x03;   //16:17
      *addr|=(make8(id,2) << 3) & 0xE0; //18:20
      *addr|=0x08;


      //sidh
      addr--;
      *addr=((make8(id,2) >> 5) & 0x07 ); //21:23
      *addr|=((make8(id,3) << 3) & 0xF8);//24:28
   }
   else {   //standard
      //eidl
      *addr=0;

      //eidh
      addr--;
      *addr=0;

      //sidl
      addr--;
      *addr=(make8(id,0) << 5) & 0xE0;

      //sidh
      addr--;
      *addr=(make8(id,0) >> 3) & 0x1F;
      *addr|=(make8(id,1) << 5) & 0xE0;
   }
}

////////////////////////////////////////////////////////////////////////////////
//
// can_set_standard_id
//
// sets a standard id
//
// Parameters:
//		addr - the address that is to be set to the id
//		id - the actual id
//
////////////////////////////////////////////////////////////////////////////////

void can_set_standard_id(int * addr, int32 id)
{
	//eidl
   *addr=0;

   //eidh
   addr--;
   *addr=0;

   //sidl
   addr--;
   *addr=(make8(id,0) << 5) & 0xE0;

   //sidh
   addr--;
   *addr=(make8(id,0) >> 3) & 0x1F;
   *addr|=(make8(id,1) << 5) & 0xE0;
}

////////////////////////////////////////////////////////////////////////////////
//
// can_set_extended_id
//
// sets an extended id
//
// Parameters:
//		addr - the address that is to be set to the id
//		id - the actual id
//
////////////////////////////////////////////////////////////////////////////////

void can_set_extended_id(int * addr, int32 id)
{
   //eidl
   *addr=make8(id,0); //0:7

   //eidh
   addr--;
   *addr=make8(id,1); //8:15

   //sidl
   addr--;
   *addr=make8(id,2) & 0x03;   //16:17
   *addr|=(make8(id,2) << 3) & 0xE0; //18:20
   *addr|=0x08;


   //sidh
   addr--;
   *addr=((make8(id,2) >> 5) & 0x07 ); //21:23
   *addr|=((make8(id,3) << 3) & 0xF8);//24:28
}

////////////////////////////////////////////////////////////////////////
//
// can_get_id()
//
// Returns the ID of the specified buffer.  (The opposite of can_set_id())
// This is used after receiving a message, to see which ID sent the message.
//
//   Paramaters:
//     addr - pointer to first byte of ID register, starting with xxxxEIDL.
//            For example, a pointer to RXM1EIDL
//     ext - Set to TRUE if this buffer uses an extended ID, FALSE if not
//
//   Returns:
//     The ID of the buffer
//
////////////////////////////////////////////////////////////////////////
int32 can_get_id(int * addr, int1 ext) {
   int32 ret;
   int * ptr;

   ret=0;
   ptr=addr;

   if (ext) {
      ret=*ptr;  //eidl

      ptr--;     //eidh
      ret|=((int32)*ptr << 8);

      ptr--;     //sidl
      ret|=((int32)*ptr & 0x03) << 16;
      ret|=((int32)*ptr & 0xE0) << 13;

      ptr--;     //sidh
      ret|=((int32)*ptr << 21);

   }
   else {
      ptr-=2;    //sidl
      ret=((int32)*ptr & 0xE0) >> 5;

      ptr--;     //sidh
      ret|=((int32)*ptr << 3);
   }

   return(ret);
}

////////////////////////////////////////////////////////////////////////////////
//
// can_get_extended_id
//
// reads the extended identification of a buffer
//
// Parameters:
//		addr - the address that is to be read
//
////////////////////////////////////////////////////////////////////////////////
int32 can_get_extended_id(int * addr)
{
	int32 ret;

	ret=*addr;  //eidl

   addr--;     //eidh
   ret|=((int32)*addr << 8);

   addr--;     //sidl
   ret|=((int32)*addr & 0x03) << 16;
   ret|=((int32)*addr & 0xE0) << 13;

   addr--;     //sidh
   ret|=((int32)*addr << 21);

	return (ret);
}

////////////////////////////////////////////////////////////////////////////////
//
// can_get_standard_id
//
// reads the standard identification of a buffer
//
// Parameters
//   	addr - the address that is to be read
//
////////////////////////////////////////////////////////////////////////////////
int32 can_get_standard_id(int * addr)
{
	int32 ret;

	addr-=2;    //sidl
   ret=((int32)*addr & 0xE0) >> 5;

   addr--;     //sidh
   ret|=((int32)*addr << 3);

	return (ret);
}

////////////////////////////////////////////////////////////////////////
//
// can_putd()
//
// Puts data on a transmit buffer, at which time the CAN peripheral will
// send when the CAN bus becomes available.
//
//    Paramaters:
//       id - ID to transmit data as
//          enumerated as - RXB0ID,RXB1ID,B0ID,B1ID,B2ID,B3ID,B4ID,B5ID
//       data - pointer to data to send
//       len - length of data to send
//       priority - priority of message.  The higher the number, the
//                  sooner the CAN peripheral will send the message.
//                  Numbers 0 through 3 are valid.
//       ext - TRUE to use an extended ID, FALSE if not
//       rtr - TRUE to set the RTR (request) bit in the ID, false if NOT
//
//    Returns:
//       If successful, it will return TRUE
//       If un-successful, will return FALSE
//
////////////////////////////////////////////////////////////////////////
int1 can_putd(int32 id, int * data, int len, int priority, int1 ext, int1 rtr) {
   int i;
   int * txd0;
   int port;

   txd0=&TXRXBaD0;

    // find emtpy transmitter
    // map access bank addresses to empty transmitter
   if (!TXB0CON.txreq) {
      CANCON.win=CAN_WIN_TX0;
		ECANCON.ewin=TX0;
      port=0;
   }
   else if (!TXB1CON.txreq) {
      CANCON.win=CAN_WIN_TX1;
		ECANCON.ewin=TX1;
      port=1;
   }
   else if (!TXB2CON.txreq) {
      CANCON.win=CAN_WIN_TX2;
		ECANCON.ewin=TX2;
      port=2;
   }
	else if (!B0CONT.txreq) {
		ECANCON.ewin=TXRX0;
		port=3;
	}
	else if (!B1CONT.txreq) {
		ECANCON.ewin=TXRX1;
		port=4;
	}
	else if (!B2CONT.txreq) {
		ECANCON.ewin=TXRX2;
		port=5;
	}
	else if (!B3CONT.txreq) {
		ECANCON.ewin=TXRX3;
		port=6;
	}
	else if (!B4CONT.txreq) {
		ECANCON.ewin=TXRX4;
		port=7;
	}
	else if (!B5CONT.txreq) {
		ECANCON.ewin=TXRX5;
		port=8;
	}
   else {
      #if CAN_DO_DEBUG
         can_debug("\r\nCAN_PUTD() FAIL: NO OPEN TX BUFFERS\r\n");
      #endif
      return(0);
   }

   //set priority.
   TXBaCON.txpri=priority;

   //set tx mask
   can_set_id(TXRXBaID, id, ext);

   //set tx data count
   TXBaDLC=len;
   TXBaDLC.rtr=rtr;

    for (i=0; i<len; i++) {
      *txd0=*data;
      txd0++;
      data++;
    }

   //enable transmission
   TXBaCON.txreq=1;

   CANCON.win=CAN_WIN_RX0;

   #if CAN_DO_DEBUG
            can_debug("\r\nCAN_PUTD(): BUFF=%U ID=%LX LEN=%U PRI=%U EXT=%U RTR=%U\r\n", port, id, len, priority, ext, rtr);
            if ((len)&&(!rtr)) {
               data-=len;
               can_debug("  DATA = ");
               for (i=0;i<len;i++) {
                  can_debug("%X ",*data);
                  data++;
               }
               can_debug("\r\n");
            }
   #endif

   return(1);
}

////////////////////////////////////////////////////////////////////////
//
// can_getd()
//
// Gets data from a receive buffer, if the data exists
//
//    Parameters:
//      id - ID who sent message
//      data - pointer to array of data
//      len - length of received data
//      stat - structure holding some information (such as which buffer
//             recieved it, ext or standard, etc)
//
//    Returns:
//      Function call returns a TRUE if there was data in a RX buffer, FALSE
//      if there was none.
//
////////////////////////////////////////////////////////////////////////
int1 can_getd(int32 & id, int * data, int & len, struct rx_stat & stat)
{
    int i;
    int * ptr;

    if (RXB0CON.rxful)
	 {

    	  CANCON.win=CAN_WIN_RX0;
		  ECANCON.ewin=RX0;				// this is if in functional mode 1 or 2
        stat.buffer=0;

	     CAN_INT_RXB0IF=0;

		  if(curfunmode)					// this will need to be updated
		  {
		  		stat.err_ovfl=COMSTAT_MODE_1.rxnovfl;
				stat.filthit=RXB0CON_MODE_1.filthit;
		  }
		  else
		  {
	     		stat.err_ovfl=COMSTAT.rx0ovfl;
   	  		COMSTAT.rx0ovfl=0;

				if (RXB0CON.rxb0dben) {
   	 			stat.filthit=RXB0CON.filthit0;
        		}
		  }
    }
    else if ( RXB1CON.rxful )
    {
        CANCON.win=CAN_WIN_RX1;
		  ECANCON.ewin=RX1;
        stat.buffer=1;

        CAN_INT_RXB1IF=0;

		  if(curfunmode)
		  {
		  		stat.err_ovfl=COMSTAT_MODE_1.rxnovfl;
				stat.filthit=RXB1CON_MODE_1.filthit;
		  }

		  else
		  {
        		stat.err_ovfl=COMSTAT.rx1ovfl;
       	 	COMSTAT.rx1ovfl=0;

        		stat.filthit=RXB1CON.filthit;
		  }
    }
	 else if ( B0CONR.rxful )
	 {
	 	  ECANCON.ewin=TXRX0;
		  stat.buffer=2;

		  CAN_INT_RXB1IF=0;			// in mode 1 and 2 this bit simply
		  									// specifies that A interrupt has occured
											// on one of the six programmable buffers
		  stat.err_ovfl=COMSTAT_MODE_1.rxnovfl;
		  stat.filthit=RXB1CON_MODE_1.filthit;

		  B0CONR.rxful=0;
	 }
	 else if ( B1CONR.rxful )
	 {
	 	  ECANCON.ewin=TXRX1;
		  stat.buffer=3;

		  CAN_INT_RXB1IF=0;

		  stat.err_ovfl=COMSTAT_MODE_1.rxnovfl;
		  stat.filthit=RXB1CON_MODE_1.filthit;

		  B1CONR.rxful=0;
	 }
	 else if ( B2CONR.rxful )
	 {
	 	  ECANCON.ewin=TXRX2;
		  stat.buffer=4;

		  CAN_INT_RXB1IF=0;

		  stat.err_ovfl=COMSTAT_MODE_1.rxnovfl;
		  stat.filthit=RXB1CON_MODE_1.filthit;

		  B2CONR.rxful=0;
	 }
	 else if ( B3CONR.rxful )
	 {
	 	  ECANCON.ewin=TXRX3;
		  stat.buffer=5;

		  CAN_INT_RXB1IF=0;

		  stat.err_ovfl=COMSTAT_MODE_1.rxnovfl;
		  stat.filthit=RXB1CON_MODE_1.filthit;

		  B3CONR.rxful=0;
	 }
	 else if ( B4CONR.rxful )
	 {
	 	  ECANCON.ewin=TXRX4;
		  stat.buffer=6;

		  CAN_INT_RXB1IF=0;

		  stat.err_ovfl=COMSTAT_MODE_1.rxnovfl;
		  stat.filthit=RXB1CON_MODE_1.filthit;

		  B4CONR.rxful=0;
	 }
	 else if ( B5CONR.rxful )
	 {
	 	  ECANCON.ewin=TXRX5;
		  stat.buffer=7;

		  CAN_INT_RXB1IF=0;

		  stat.err_ovfl=COMSTAT_MODE_1.rxnovfl;
		  stat.filthit=RXB1CON_MODE_1.filthit;

		  B5CONR.rxful=0;
	 }
    else
	 {
      #if CAN_DO_DEBUG
         can_debug("\r\nFAIL ON CAN_GETD(): NO MESSAGE IN BUFFER\r\n");
      #endif
      return (0);
    }

    len = RXBaDLC.dlc;
    stat.rtr=RXBaDLC.rtr;

    stat.ext=TXRXBaSIDL.ext;
    id=can_get_id(TXRXBaID,stat.ext);

    ptr = &TXRXBaD0;
    for ( i = 0; i < len; i++ ) {
        *data = *ptr;
        data++;
        ptr++;
    }

	 // if in mode 1 or 2 it is necesary to clear B0-B5 rxfi
	 if(curfunmode)
	 	B0CONR.rxful=0;

    // return to default addressing
    CANCON.win=CAN_WIN_RX0;

    stat.inv=CAN_INT_IRXIF;
    CAN_INT_IRXIF = 0;

    if (stat.buffer) {
      RXB1CON.rxful=0;
    }
    else {
      RXB0CON.rxful=0;
    }

    #if CAN_DO_DEBUG
       can_debug("\r\nCAN_GETD(): BUFF=%U ID=%LX LEN=%U OVF=%U ", stat.buffer, id, len, stat.err_ovfl);
       can_debug("FILT=%U RTR=%U EXT=%U INV=%U", stat.filthit, stat.rtr, stat.ext, stat.inv);
       if ((len)&&(!stat.rtr)) {
          data-=len;
          can_debug("\r\n    DATA = ");
          for (i=0;i<len;i++) {
            can_debug("%X ",*data);
            data++;
          }
       }
       can_debug("\r\n");
    #endif

    return(1);
}

////////////////////////////////////////////////////////////////////////////////
//
// can_enable_b_transfer: mode 1 & 2
//
// Sets one of the 6 programmable buffers to be a transfer buffer.  This uses
// a simple bitwise operation so that more than one buffer can be set at a
// time.
//
// The register that contains the TX/RX information is BSEL0 and the control
//	bits take up the 6 most significant bits.  Therefore a value of 0x04 would
//	set B0 as a transmit buffer while a value of 0xFC would set all of the
// programmable buffers to transmit buffers.
//
//	Parameters:
//		b - the buffer which is to become a transfer buffer
//       enumerated as - B0,B1,B2,B3,B4,B5
//
// More information can be found on the programmable buffers in the PIC18F4580
//	datasheet, section 23.5.3
//
////////////////////////////////////////////////////////////////////////////////

#define can_enable_b_transfer(b) (BSEL0.btxen|=b);

////////////////////////////////////////////////////////////////////////////////
//
// can_enable_b_receiver: mode 1 & 2
//
// Sets one of the 6 programmable buffers to be a receiver buffer.  This uses
// a simple bitwise operation so that more than one buffer can be set at a
// time.
//
// The register that contains the TX/RX information is BSEL0 and the control
//	bits take up the 6 most significant bits.  Therefore a value of 0x04 would
//	set B0 as a receive buffer while a value of 0xFC would set all of the
// programmable buffers to receive buffers.
//
// Parameters:
// 	b - the buffer which is to become a receiver buffer
//       enumerated as - B0,B1,B2,B3,B4,B5
//
// returns:
//		void
//
// More information can be found on the programmable buffers in the PIC18F4580
// datasheet, section 23.5.3
//
////////////////////////////////////////////////////////////////////////////////

#define can_enable_b_receiver(b) (BSEL0.btxen&=~b);

////////////////////////////////////////////////////////////////////////////////
//
// can_enable_rtr: mode 1 & 2
//
// Prepares one of the programmable registers to be used as an Auto-rtr buffer
//	This function allows for multiple rtr enables.
//
// Parameters:
//		b - the programmable buffer to be set to Auto-rtr mode
//       enumerated as - B0,B1,B2,B3,B4,B5
//
//		b=0x04 - B0 rtr enable
//		b=0x08 - B1 rtr enable
//		b=0x10 - B2 rtr enable
//		b=0x20 - B3 rtr enable
// 	b=0x40 - B4 rtr enable
//		b=0x80 -	B5 rtr enable
//
//		any logical and (&) combination of the above will also work
//
//		b = 0x04 & 0x80 = 0x84 - B0 and B5 rtr enable
//
// returns:
//  	void
//
// More information can be found on Auto-rtr in the PIC18F4580 datasheet,
//	section 23.5.4
//
////////////////////////////////////////////////////////////////////////////////

void  can_enable_rtr(PROG_BUFFER b)
{

	can_enable_b_transfer ( b );

	if(bit_test(b,2))
		B0CONTA|=0x04;
	if(bit_test(b,3))
		B1CONTA|=0x04;
	if(bit_test(b,4))
		B2CONTA|=0x04;
	if(bit_test(b,5))
		B3CONTA|=0x04;
	if(bit_test(b,6))
		B4CONTA|=0x04;
	if(bit_test(b,7))
		B5CONTA|=0x04;

}

////////////////////////////////////////////////////////////////////////////////
//
// can_disable_rtr: mode 1 & 2
//
// disables certain programmable registers from being used as Auto-rtr buffers
//	This function allows for multiple rtr disables.
//
// Parameters:
//		b - the programmable buffer to be set to Auto-rtr mode
//       enumerated as B0,B1,B2,B3,B4,B5
//
//		b=0x04 - B0 rtr disable
//		b=0x08 - B1 rtr disable
//		b=0x10 - B2 rtr disable
//		b=0x20 - B3 rtr disable
// 	b=0x40 - B4 rtr disable
//		b=0x80 -	B5 rtr disable
//
//		any logical or (|) combination of the above will also work
//
//		b = 0x04 | 0x80 = 0x84 - B0 and B5 rtr disable
//
// returns:
//  	void
//
// More information can be found on Auto-rtr in the PIC18F4580 datasheet,
//	section 23.5.4
//
////////////////////////////////////////////////////////////////////////////////

void can_disable_rtr(PROG_BUFFER b)
{
	if(bit_test(b,2))
		B0CONTA&=0xfb;
	if(bit_test(b,3))
		B1CONTA&=0xfb;
	if(bit_test(b,4))
		B2CONTA&=0xfb;
	if(bit_test(b,5))
		B3CONTA&=0xfb;
	if(bit_test(b,6))
		B4CONTA&=0xfb;
	if(bit_test(b,7))
		B5CONTA&=0xfb;
}

////////////////////////////////////////////////////////////////////////////////
//
// can_load_rtr: mode 1 & 2
//
//	Loads a SINGLE b buffer with data to be sent on the occurence of an rtr.
//
// Parameters:
//
//		b - The programmable buffer to be filled
//       enumerated as - B0,B1,B2,B3,B4,B5
//		data - the address of the first data byte
//		len - the number of data bytes to be copied
//
// Returns:
//		void
//
//	Note, the programmer must set the appropriate rtr registers in order for the
//			rtr function to work.  This function does not set any of those
//			registers.  For example, to enable B0 as an Auto-rtr buffer, the
//			functions:
//
//			can_enable_b_transfer(B0);
//			can_enable_rtr(B0);
//			function to link acceptance filter to B0
//
//			need to be called.
//
//	can_load_rtr does no damage to the current mode of the ECAN
//
// More information on the Auto-rtr can be found in the PIC18F4580 datasheet
// section 23.5.4
//
////////////////////////////////////////////////////////////////////////////////
void can_load_rtr (PROG_BUFFER b, int * data, int len)
{

	int * ptr;

	//do no damage to the current mode;
	curmode = CANSTAT.opmode;

	can_set_mode(CAN_OP_CONFIG);

	if(bit_test(b,2))
   {
		ptr=&B0D0;
      B0DLCT=len;
   }
	else if (bit_test(b,3))
   {
		ptr=&B1D0;
      B1DLCT=len;
   }
	else if (bit_test(b,4))
   {
		ptr=&B2D0;
      B2DLCT=len;
   }
	else if (bit_test(b,5))
   {
		ptr=&B3D0;
      B3DLCT=len;
   }
	else if (bit_test(b,6))
   {
		ptr=&B4D0;
      B4DLCT=len;
   }
	else if (bit_test(b,7))
   {
		ptr=&B5D0;
      B5DLCT=Len;
   }
	else
		return;

	for(;len>0;len--) {
		*ptr=*data;
		ptr++;
		data++;
	}

	can_set_mode(curmode);
}

////////////////////////////////////////////////////////////////////////////////
//
// can_enable_filter: mode 1 , 2 & 3
//
//	Enables a given acceptance filter
//
// Parameters:
//		filter - the filter that is to be enabled
//			enumerated as - RXF0EN-RXF15EN
//
// Returns:
// 	void
//
// More information can be found on Acceptance Filters in the PIC18F4580
// datasheet, Section 23.8
//
////////////////////////////////////////////////////////////////////////////////
void can_enable_filter(long filter)
{
	long * ptr;

	curmode=CANSTAT.opmode;

	CAN_SET_MODE(CAN_OP_CONFIG);

	ptr = &RXFCON0;

	*ptr|=filter;

	CAN_SET_MODE(curmode);
}

////////////////////////////////////////////////////////////////////////////////
//
// can_disable_filter: mode 0 , 1 & 2
//
// Disables a given acceptance filter
//
// Parameters:
//		filter - the filter that is to be disabled
//		  enumerated as - RXF0EN-RXF15EN
//
// Returns:
//		void;
//
// More information can be found on Acceptance Filters in the PIC18F4580
// datasheet, Section 23.8
//
////////////////////////////////////////////////////////////////////////////////
void can_disable_filter(long filter)
{
	long * ptr;

	curmode=CANSTAT.opmode;

	CAN_SET_MODE(CAN_OP_CONFIG);

	ptr = &RXFCON0;

	*ptr&=~filter;

	CAN_SET_MODE(curmode);
}

////////////////////////////////////////////////////////////////////////////////
//
// can_associate_filter_to_buffer: mode 1 & 2
//
// Associates a given buffer with a given filter register
//
// Parameters:
//		buffer - the buffer that is to be associated with the filter
//		  enumerated as
//					ARXB0-ARXB1 - Dedicated recieve buffers RX0-RX1
//					AB0-AB5 - Programmable recieve buffers B0-B5
//
//		filter - the filter that is to be associated with the buffer
//			enumerated as
//					F0BP-F15BP - Filters 0 - 15
//
//
// Returns:
//		void
//
//	More information can be found on Acceptance Filters in the PIC18F4580
// datasheet, Section 23.8
//
////////////////////////////////////////////////////////////////////////////////
void can_associate_filter_to_buffer(CAN_FILTER_ASSOCIATION_BUFFERS buffer, CAN_FILTER_ASSOCIATION filter)
{
	int * ptr;

	curmode=CANSTAT.opmode;

	CAN_SET_MODE(CAN_OP_CONFIG);

	ptr=(filter>>1)|0x0DE0;

	if((filter & 0x01) == 1)
	{
		*ptr&=0x0f;
		*ptr|=buffer<<4;
	}
	else
	{
		*ptr&=0xf0;
		*ptr|=buffer;
	}

	CAN_SET_MODE(curmode);
}

////////////////////////////////////////////////////////////////////////////////
//
// can_associate_filter_to_mask
//
//	Associates a given filter to a given mask
//
//	Parameters:
//		mask - the mask that is to be associated with the filter
//			enumerated as
//				ACCEPTANCE_MASK_0
//				ACCEPTANCE_MASK_1
//				FILTER_15
//				NO_MASK
//
//		filter - the filter that is to be associated with the mask
//			enumerated as
//					F0BP-F15BP - Filters 0 - 15
//
//
//	Returns:
//		void
//
// More information can be foun on Acceptance Filters in the PIC18F4580
// datasheet, Section 23.8
//
////////////////////////////////////////////////////////////////////////////////
void can_associate_filter_to_mask(CAN_MASK_FILTER_ASSOCIATE mask, CAN_FILTER_ASSOCIATION filter)
{
	int * ptr;

	curmode = CANSTAT.opmode;

	CAN_SET_MODE(CAN_OP_CONFIG);

	ptr=(filter>>2)|0x0DF0;

	if((filter & 0x03)==0)
	{
		*ptr&=0xfc;
		*ptr|=mask;
	}
	else if((filter & 0x03)==1)
	{
		*ptr&=0xf3;
		*ptr|=mask<<2;
	}
	else if((filter & 0x03)==2)
	{
		*ptr&=0xcf;
		*ptr|=mask<<4;
	}
	else if((filter & 0x03)==3)
	{
		*ptr&=0x3f;
		*ptr|=mask<<6;
	}

	CAN_SET_MODE(curmode);
}

////////////////////////////////////////////////////////////////////////////////
//
// can_FIFO_getd
//
// Retreives data in Mode 2
//
// Parameters:
//		id - The ID of the sender
//		data - Address of the array to store the data in
//		len - number of data bytes to read
//		stat - status structure to return infromation about the receive register
//
// Returns:
//		int1 - TRUE if there was data in the buffer, FALSE if there wasn't
//
// More information can be found on the FIFO mode in the PIC18F4580 datasheet
// section 23.7.3
//
////////////////////////////////////////////////////////////////////////////////
int1 can_fifo_getd(int32 & id, int * data, int &len, struct rx_stat & stat )
{

	int i;
	int *ptr;

	if(!COMSTAT_MODE_2.fifoempty)			// if there is no data in the buffer
		return(0);								// return false;

	ECANCON.ewin=CANCON_MODE_2.fp | 0x10;
	stat.buffer=CANCON_MODE_2.fp;

	CAN_INT_RXB1IF=0;

	stat.err_ovfl=COMSTAT_MODE_2.rxnovfl;
	stat.filthit=RXB0CON_MODE_2.filthit;

	len = RXBaDLC.dlc;
   stat.rtr=RXBaDLC.rtr;

   stat.ext=TXRXBaSIDL.ext;
   id=can_get_id(TXRXBaID,stat.ext);

	ptr = &TXRXBaD0;
   for ( i = 0; i < len; i++ ) {
       *data = *ptr;
       data++;
       ptr++;
   }

	RXB0CON_MODE_2.rxful=0;

   // return to default addressing
   ECANCON.ewin=RX0;

   stat.inv=CAN_INT_IRXIF;
   CAN_INT_IRXIF = 0;

	return(1);
}

////////////////////////////////////////////////////////////////////////////////
//
// can_t0_putd - can_t2_putd
// can_b0_putd - can_b5_putd
//
// places data to be transfered in a specified buffer
//
// Parameters:
//		id - id that will be sent with the data
// 	data - pointer to the data
//		len - number of data bytes (0-8)
//		pri - priority (0-3)
//		ext - extended or not
// 	rtr - request remote transfer
//
// Returns:
//		TRUE if data is succesfully loaded into the buffer
//		FALSE if data can not be loaded into the buffer
//
//	Notes
//		- make sure that the desired buffer is set to be a trasfer buffer
//		  using the can_enable_b_transfer ( ) function
//
// More information can be found on using the transfer buffers in the PICF4580
//	datasheet section 23.6
//
////////////////////////////////////////////////////////////////////////////////

// transfer buffer 0
int1 can_t0_putd(int32 id, int * data, int len, int pri, int1 ext, int1 rtr)
{
	int * ptr;

	if(TXB0CON.txreq)
		return ( FALSE );

	can_set_id( TXB0ID, id, ext );

	TXB0DLC.dlc = len;

	TXB0CON.txpri = pri;

	TXB0DLC.rtr = rtr;

	ptr = &TXB0D0;

	for(;len>0;len--)
	{
		*ptr = *data;
		ptr++;
		data++;
	}

	TXB0CON.txreq = 1;

	return ( TRUE );
}

// trasfer buffer 1
int1 can_t1_putd(int32 id, int * data, int len, int pri, int1 ext, int1 rtr)
{
	int * ptr;

	if(TXB1CON.txreq)
		return ( FALSE );

	can_set_id( TXB1ID, id, ext );

	TXB1DLC.dlc = len;

	TXB1CON.txpri = pri;

	TXB1DLC.rtr = rtr;

	ptr = &TXB1D0;

	for(;len>0;len--)
	{
		*ptr = *data;
		ptr++;
		data++;
	}

	TXB1CON.txreq = 1;

	return ( TRUE );
}

// transfer buffer 2
int1 can_t2_putd(int32 id, int * data, int len, int pri, int1 ext, int1 rtr)
{
	int * ptr;

	if(TXB2CON.txreq)
		return ( FALSE );

	can_set_id( TXB2ID, id, ext );

	TXB2DLC.dlc = len;

	TXB2CON.txpri = pri;

	TXB2DLC.rtr = rtr;

	ptr = &TXB2D0;

	for(;len>0;len--)
	{
		*ptr = *data;
		ptr++;
		data++;
	}

	TXB2CON.txreq = 1;

	return ( TRUE );
}

// programmable buffer 0
int1 can_b0_putd(int32 id, int * data, int len, int pri, int1 ext, int1 rtr)
{
   int * txd0;

   txd0=&TXRXBaD0;

   if (B0CONT.txreq)
		return ( FALSE );

	ECANCON.ewin=TXRX0;

	 //set priority.
   TXBaCON.txpri=pri;

   //set tx mask
   can_set_id(TXRXBaID, id, ext);

   //set tx data count
   TXBaDLC=len;
   TXBaDLC.rtr=rtr;

    for (;len>0;len--)
	 {
      *txd0=*data;
      txd0++;
      data++;
    }

   //enable transmission
   TXBaCON.txreq=1;

	return ( TRUE );

}

// programmable buffer 1
int1 can_b1_putd(int32 id, int * data, int len, int pri, int1 ext, int1 rtr)
{
	int * txd0;

   txd0=&TXRXBaD0;

   if (B1CONT.txreq)
		return ( FALSE );

	ECANCON.ewin=TXRX1;

	 //set priority.
   TXBaCON.txpri=pri;

   //set tx mask
   can_set_id(TXRXBaID, id, ext);

   //set tx data count
   TXBaDLC=len;
   TXBaDLC.rtr=rtr;

    for (;len>0;len--)
	 {
      *txd0=*data;
      txd0++;
      data++;
    }

   //enable transmission
   TXBaCON.txreq=1;

	return ( TRUE );
}

// programmable buffer 2
int1 can_b2_putd(int32 id, int * data, int len, int pri, int1 ext, int1 rtr)
{
	int * txd0;

   txd0=&TXRXBaD0;

   if (B2CONT.txreq)
		return ( FALSE );

	ECANCON.ewin=TXRX2;

	 //set priority.
   TXBaCON.txpri=pri;

   //set tx mask
   can_set_id(TXRXBaID, id, ext);

   //set tx data count
   TXBaDLC=len;
   TXBaDLC.rtr=rtr;

    for (;len>0;len--)
	 {
      *txd0=*data;
      txd0++;
      data++;
    }

   //enable transmission
   TXBaCON.txreq=1;

	return ( TRUE );
}

// programmable buffer 3
int1 can_b3_putd(int32 id, int * data, int len, int pri, int1 ext, int1 rtr)
{
   int * txd0;

   txd0=&TXRXBaD0;

   if (B3CONT.txreq)
		return ( FALSE );

	ECANCON.ewin=TXRX3;

	 //set priority.
   TXBaCON.txpri=pri;

   //set tx mask
   can_set_id(TXRXBaID, id, ext);

   //set tx data count
   TXBaDLC=len;
   TXBaDLC.rtr=rtr;

    for (;len>0;len--)
	 {
      *txd0=*data;
      txd0++;
      data++;
    }

   //enable transmission
   TXBaCON.txreq=1;

	return ( TRUE );

}

// programmable buffer 4
int1 can_b4_putd(int32 id, int * data, int len, int pri, int1 ext, int1 rtr)
{
	int * txd0;

   txd0=&TXRXBaD0;

   if (B4CONT.txreq)
		return ( FALSE );

	ECANCON.ewin=TXRX4;

	 //set priority.
   TXBaCON.txpri=pri;

   //set tx mask
   can_set_id(TXRXBaID, id, ext);

   //set tx data count
   TXBaDLC=len;
   TXBaDLC.rtr=rtr;

    for (;len>0;len--)
	 {
      *txd0=*data;
      txd0++;
      data++;
    }

   //enable transmission
   TXBaCON.txreq=1;

	return ( TRUE );
}

// programmable buffer 5
int1 can_b5_putd(int32 id, int * data, int len, int pri, int1 ext, int1 rtr)
{
	int i;
	int * txd0;

   txd0=&TXRXBaD0;

   if (B5CONT.txreq)
		return ( FALSE );

	ECANCON.ewin=TXRX5;

	 //set priority.
   TXBaCON.txpri=pri;

   //set tx mask
   can_set_id(TXRXBaID, id, ext);

   //set tx data count
   TXBaDLC=len;
   TXBaDLC.rtr=rtr;

   for (;len>0;len--)
	{
     *txd0=*data;
     txd0++;
     data++;
   }

	txd0=&B5D0;
	for(i=0;i<8;i++)
	{
	 	printf("%i ",txd0[i]);
	}
	printf("\n\r\n\r");

   //enable transmission
   TXBaCON.txreq=1;

	return ( TRUE );
}

