/**
 * \file INCAN16X.C
 * 
 * \author Axel Wolf, SCI Cupertino
 * \author Dr. Jens Barrenscheen, HL MC PD, Munich
 * \author Hubert Piontek, University of Ulm
 *
 * Routine for initializing the CAN module of the C166
 *
 * Most of this is based von the Infineon/Siemens Application Note AP2922.
 * Some additions made at University of Ulm, February 2003.
 *
 * This CAN driver is mainly meant to be used by the publisher/subscriber
 * library developed at the University of Ulm, 1999-2003.
 */

/*********************************************************************
 * Program name:	"INCAN16X.C"                                     *
 * Compiler used:	BSO/Tasking C166                                 *
 * Task:		Source File for procedure can_init_16x               *
 *			belonging to Siemens ApNote AP2922                       *
 *			"'C' CAN Driver Routines for the C166 family"            *
 *                                                                   * 
 * Last modifications:	April 28nd 1997                              *
 * Version:		1.0                                                  *
 * Authors:		Axel Wolf,  SCI Cupertino                            *
 *			Dr. Jens Barrenscheen, HL MC PD, Munich                  *
 *********************************************************************/

/* ----------------------------------- include files: -------------- */
#include <REG167.H>         /* register definitions C167             */
#include <CANR_16X.H>       /* CAN control register definitions      */
#include <intrins.h>

/**
 * \defgroup baudrates Bit Timing values
 */
/*@{*/
/// Bit timing for 50kBit/s 
#define BTR_VALUE_50KBAUD	0x7aC9
/// Bit timing for 125kBit/s
#define BTR_VALUE_125KBAUD	0x7aC3
/// Bit timing for 250kBit/s
#define BTR_VALUE_250KBAUD	0x7aC1
/// Bit timing for 500kBit/s
#define BTR_VALUE_500KBAUD	0x7aC0
/// Bit timing for 1MBit/s
#define BTR_VALUE_1MBAUD	0x25c0
/*@}*/

/**
 * \defgroup msgsfrs SFRs for the message objects
 */
/*@{*/
/// Message IDs; pointers to the UARs (see C166 manuals)
unsigned int *id_ptr_16x[16];
/// First data bytes
unsigned char *db0_ptr_16x[16];
/// Message Control registers
unsigned int *msgctrl_ptr_16x[16];
/// Message Configuration registers
unsigned char *msgconf_ptr_16x[16];
/*@}*/

/**
 * \defgroup globs Global variables for the CAN driver.
 */
/*@{*/
/// Stores the directions (transmit or receive) of all message objects
unsigned char dir_bit_16x[16];
/// Stores the frame format (extended or standard) of all message objects
unsigned char xtd_bit_16x[16];
/// Stores the data length configurations of all message objects
unsigned char dlc_16x[16];
/*@}*/

/**
 * This function must be called before any CAN communication can take place. It resets the CAN controller, sets
 * the baud rate and enables interrupts (if specified) for errors, status changes, and globally for the CAN controller.
 *
 * \param baud_rate Baud rate in kBit/s. You can specify 50, 125, 250, 500 or 1000. 
 *                  If you specify anything else, the CAN bus will be set to 500kBit/s as a default.
 * \param eie Flag whether to enable Error Interrupts (see C166 manuals)
 * \param sie Flag whether to enable Status Change Interrupts (see C166 manuals)
 * \param ie Flag whether to enable Interrupt propagation from the CAN module to the C166 core
 */
void init_can_16x(unsigned int baud_rate, unsigned char eie,
	unsigned char sie, unsigned char ie)
{       
	unsigned char i, n;
	unsigned char *dummy_dbptr;

	/* Initialization PORT4 (CAN) (P4.6 to output; P4.5 to input): */
	_bfld_ (P4, 0x0060, 0x0060);
	_bfld_ (DP4, 0x0060, 0x0040);

	/* Load C167 pointers: */
	for (i=1;i<16;i++) {
		/* set pointers to data bytes 0 of MO 1..15 */
		db0_ptr_16x[i] = (unsigned char *)(0xef07+i*16);
		/* set pointers to id's of MO 1..15 (UARs) */
	   	id_ptr_16x[i] = (unsigned int *)(0xef02+i*16);
		/* set pointers to Message Conf. Registers of MO 1..15 */	
	   	msgconf_ptr_16x[i] = (unsigned char *)(0xef06+i*16);
		/* set pointers to Message Control Registers of MO 1..15 */
	   	msgctrl_ptr_16x[i] = (unsigned int *)(0xef00+i*16);
		
	   	dir_bit_16x[i] = 0;		/* clear DIR bit array */
	   	xtd_bit_16x[i] = 0;		/* clear XTD bit array */
	   	dlc_16x[i] = 0;			/* clear data length code array */
	}

	/* Load General CAN-Registers: */
	CR=0x41;	/* set CCE and INIT in Control Register (EF00h) */
	SR=0x00;	/* Clear Status Partition (EF01h) */

	switch (baud_rate) {
		case 50:	BTR=BTR_VALUE_50KBAUD;
					break;
	   	case 125:	BTR=BTR_VALUE_125KBAUD;
					break;
	   	case 250:	BTR=BTR_VALUE_250KBAUD;
					break;
	   	case 500:	BTR=BTR_VALUE_500KBAUD;
					break;
	   	case 1000:	BTR=BTR_VALUE_1MBAUD;
					break;
	   	default:	BTR=BTR_VALUE_500KBAUD;
					break;
	}
	/* 0 1 1 1  1 0 1 0  1 1 0 0  0 0 0 0 = 500 kBit/s @ 20MHz  */
	/* - TSEG2   TSEG1   SJW|<--  BRP -->|                      */

	/* each bit of standard ID must match to store mess. */
	GMS=0xe0ff;	/* Global Mask Short (EF06h) */

	/* each bit of extended ID must match to store mess. */
	UGML=0xffff;	/* Upper Global Mask Long (EF08h) */
	LGML=0xf8ff;	/* Lower Global Mask Long (EF0Ah) */
			
	/* every message into MO 15 (Basic CAN Feature)*/
	UMLM=0x0000;	/* Upper Mask of Last Message (EF0Ch) */
	LMLM=0x0000;	/* Lower Mask of Last Message (EF0Eh) */
			
	/* reset all elements incl MSGVAL in all Message Object Ctrl. Reg.: */
	for (i=1;i<16;i++) *msgctrl_ptr_16x[i] = 0x5555;

	/* reset all data bytes in all Message Objects: */
	for (i=1;i<16;i++) {
	   	dummy_dbptr=db0_ptr_16x[i];	
	   	for (n=0;n<8;n++) 
			*dummy_dbptr++ = 0x00;
	}

	/* end initialization (CCE=0, INIT=0); Interrupts EIE, SIE, IE=user: */
	CR = (0x00 | (eie<<3) | (sie<<2) | (ie<<1));
}