#ifndef __canr_16x_h
#define __canr_16x_h

/**
 * \file CANR_16X.H
 * 
 * \author Axel Wolf, SCI Cupertino
 * \author Dr. Jens Barrenscheen, HL MC PD, Munich
 * \author Hubert Piontek, University of Ulm
 *
 * CAN Driver include file for the C166 family. $Id: CANR_16X.H,v 1.1 2003/07/15 11:38:59 hp Exp $
 * This file contains the definitions for the CAN driver for the C166 family.
 * 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.
 */

/**
 * \mainpage CAN Driver library for the C166 family
 *
 * \section Introduction
 *
 * This library provides a more convienient API to the CAN controller
 * of the C166 family of microcontrollers than the <i>Special Function Registers</i>
 * (SFRs) themselves. The library is based on the Siemens/Infineon Application Note AP2922.
 * It was extended and modified in a few ways to further enhance convienience and fully 
 * support the publisher/subscriber library developed at the University of Ulm.
 * 
 * \section API
 *
 * The API consists of a total of 13 functions, and one typedef'd struct:
 * -# init_can_16x()
 * -# def_mo_16x()
 * -# undef_mo_16x()
 * -# ld_modata_16x()
 * -# send_mo_16x()
 * -# rd_modata_16x()
 * -# rd_mo15_16x()
 * -# check_mo_16x()
 * -# check_mo15_16x()
 * -# check_busoff_16x()
 * -# set_global_mask()
 * -# can_write()
 * -# can_read()
 * -# ::canmsg
 *
 * \section Usage
 *
 * \subsection Enabling the CAN module
 *
 * To use the CAN controller on the C166, together with this library, you must make sure
 * that access to the on-chip CAN and XRAM is enabled with your compiler.
 * Also check any startup-code that is involved, so that it enables the CAN module and don't 
 * forget to set the XPEN bit in the SYSCON register, 
 * as this also controls the CAN controller for newer versions of the C167CR (steppings ES-GA, 
 * GA, GA-T, GA-T 6, ES-JA and later; see also Infineon Errata Sheet for the C167CR, Release 1.2,
 * June 18, 2001) and may not be documented in your version of the C167 manual.
 *
 * For a quick-start with the KEIL Compiler suite, make sure that in the "Options for Target XXX"
 * dialog, you have the following settings:
 *
 * - Tab Target: set the Memory Model to HLarge, and check the Use On-Chip CAN+XRAM checkbox.
 *   If using a Phytec MM167 module, enter for External Memory locations #1 type ROM, start
 *   address 0x00000, size 0x40000, and for #2 type RAM, start address 0x40000, size 0x40000.
 * - Tab Output: select Create Library and set the output filename to canlib.lib if you want 
 *   to (re)create the library.
 *
 * If you want to use the (pre-compiled) CAN library with the KEIL suite, select "Add files to Group",
 * and look for the library file (default is canlib.lib). Then look for CANR_16X.H and add that one
 * too; it contains all the prototypes of the CAN library.
 *
 * In your application project, make sure, that you set the Target Options as described above. They must match
 * for all libraries used, and the application project itself. For the application, you also
 * must edit the assembly startup file, for me, it's called START167.A66, and was just magically there
 * on the PC. If you need it, contact me.
 * In that file, you need to change the following definitions:
 * - _XPEN EQU 1 to enable the CAN module
 * - $SET (BUSCON1 = 1)
 * - \%DEFINE (ADDRESS1) (040000H)
 * - \%DEFINE (RANGE1) (256K)
 * - $SET (BUSCON4 = 1)
 * - \%DEFINE (ADDRESS4) (100000H)
 * - \%DEFINE (RANGE4) (4K)
 *
 * \subsection Initializing the CAN module
 *
 * To initialize the CAN module, call the init_can_16x() function. It will reset the CAN
 * module, and configure it to your needs. 
 *
 * Before sending or receiving any message through one of the 15 so-called <i>message objects</i>
 * of the C166 CAN module, these message objects must be "defined" (configured). Use def_mo_16x()
 * for that. 
 *
 * Before sending a CAN message with payload, you need to load the payload into the corresponding 
 * message object. This can be done using ld_modata_16x().
 *
 * Sending the message is finally triggered by calling send_mo_16x().
 *
 * For reception of CAN messages, you can check a message object by calling check_mo_16x() (for message objects 1 through 14) or
 * check_mo15_16x() (for message object 15). If the return value of these messages is "true", then
 * a new message arrived and can be read using read_modata_16x() and rd_mo15_16x(), respectively.
 *
 * The function check_busoff_16x() can be used for some basic error checking and recovery in case
 * of a <i>busoff</i> state.
 *
 * After initialization, the <i>global mask</i> for message objects 1 through 14 is set in a way
 * that for a successful reception of a message, all identifier bits of the message must match the
 * repective identifier bits of the message object. Message object 15, on the other hand, is
 * configured to be able receive all messages, regardless of their identifier, unless they already
 * could be matched to a properly configured message object 1..14. To change this behaviour for
 * the message objects 1..14, use set_global_mask().
 *
 * If you are done using a configured message object and don't want to be bothered by it anymore,
 * use undef_mo_16x() to disable it.
 *
 * Finally, can_write() and can_read() give you some nice wrappers for some of the above functions.
 * As one of their parameters, they take a pointer to a ::canmsg structure, holding a complete
 * can message. can_write() always uses message object 1 to send CAN messages. can_read() can be
 * used on any of the message objects 2..14. These functions are mainly meant to be used by
 * the publisher/subscriber library, but can save some typing in other cases, too ;).
 *
 * \subsection Hints
 *
 * Do not access the CAN controller by any other means than this library. Better yet, do not use
 * this library directly, but use the publisher/subscriber library. It's even more convienient to
 * use, and you don't need to bother with a lot of low-level things.
 *
 * This library doesn't support the interrupt generation feature of the CAN controller for now.
 * If you enable interrupts, you need to write your own interrupt service routines.
 *
 */

#include "../sys/time.h"

/* ----------------------------------------- header: ----------------*/
/*********************************************************************
 * Program name:	"CANR_16X.H"                                     *
 * Task:		Include file                                         *
 *			belonging to Siemens ApNote AP2922                       *
 *			"'C' CAN Driver Routines for the C166 family"            *
 *                                                                   * 
 * Last modifications:	Feb 24th 2003                                *
 * Version:		1.1                                                  *
 * Authors:		Axel Wolf,  SCI Cupertino                            *
 *			Dr. Jens Barrenscheen, HL MC PD, Munich                  *
 *			Hubert Piontek, Uni Ulm                                  *
 *********************************************************************/

/**
 * \defgroup canregs CAN registers
 *
 * \brief definitions of CAN module control registers
 *
 * The C166 CAN module has 9 SFRs dedicated to it. They are
 * used to control it, set the baudrate, set message masks, and other things.
 */
/*@{*/

/// The Command register
#define 	CR	*(unsigned char*) 0xef00
/// The Status register
#define 	SR	*(unsigned char*) 0xef01
/// The Interrupt register
#define 	IR	*(unsigned char*) 0xef02
/// The baudrate register
#define 	BTR	*(unsigned int *) 0xef04
/// The global short mask (11 Bit IDs)
#define 	GMS	*(unsigned int *) 0xef06
/// The upper half of the global long mask (29 Bit IDs)
#define 	UGML	*(unsigned int *) 0xef08
/// The lower half of the global long mask (29 Bit IDs)
#define 	LGML	*(unsigned int *) 0xef0a
/// The upper half of the long mask for the last message
#define 	UMLM	*(unsigned int *) 0xef0c
/// The lower half of the long mask for the last message
#define 	LMLM	*(unsigned int *) 0xef0e
/*@}*/

/// The interrupt vector of the CAN module
#define		CAN_INTERRUPT	0x40

/**
 * \defgroup msgconsts Constants for defining Message Objects
 *
 * \brief these defines can be used to make the definition of message objects more readable
 */
/*@{*/
/// Use the extended frame format with 29 bit identifiers
#define		USE_XTID		1
/// Use the standard frame format with 11 bit identifiers
#define		USE_STID		0
/// Make the message object a transmit object
#define		DIR_XMIT		1
/// Make the message object a receive object
#define		DIR_RECV		0
/// Disable transmit interrupts
#define		NO_TX_INT		0
/// Disable receive interrupts
#define		NO_RX_INT		0
/// Enable transmit interrupts
#define		TX_INT			1
/// Enable receive interrupts
#define		RX_INT			1
/*@}*/

/**
 * \defgroup canapi CAN controller API functions
 */

/*@{*/

/**
 * \brief Initialize the CAN module
 */
void init_can_16x(unsigned int baud_rate, unsigned char eie,
	unsigned char sie, unsigned char ie);

/**
 * \brief Send a message object
 */
void send_mo_16x(unsigned char nr);

/**
 * \brief Read data from a message object 
 */
void rd_modata_16x(unsigned char nr, unsigned char *downl_data_ptr, unsigned long *mo_id_ptr, unsigned char *mo_dlc_ptr);

/**
 * \brief Read data from the last message object
 */
void rd_mo15_16x(unsigned char *mo15_db_ptr,
	unsigned long *mo15_id_ptr, unsigned char *mo15_dlc_ptr);

/**
 * \brief Load data into a message object
 */
void ld_modata_16x(unsigned char nr, unsigned char *upl_data_ptr);

/**
 * \brief Define a message object
 */
void def_mo_16x(unsigned char nr, unsigned char xtd, unsigned long id,
	unsigned char dir, unsigned char dlc, unsigned char txie,
	unsigned char rxie);

/**
 * \brief Clear a message object
 */
void undef_mo_16x( unsigned char nr );

/**
 * \brief Check a message object for freshly received data
 */
unsigned char check_mo_16x(unsigned char nr);

/**
 * \brief Check the last message object for new data
 */
unsigned char check_mo15_16x(void);

/**
 * \brief Checks for a busoff state of the controller
 */
unsigned char check_busoff_16x(void);

/**
 * \brief Sets the global reception mask.
 */
void set_global_mask( unsigned long mask );

/**
 * \brief Structure for a can message 
 *
 * This is mainly used by the publisher/subscriber library to transmit and receive
 * messages.
 */
typedef struct {
  unsigned long id;		///< message identifier
  int rtr;              ///< remote transmission request flag
  int len;              ///< data length (0..8)
  unsigned char d[8];   ///< the data
  time_t timestamp;     ///< time when it was sent or received
} canmsg;

/**
 * \brief Send a can message
 */
void can_write(canmsg *cm);

/**
 * \brief Try reading a can message
 */
int can_read(int nr, canmsg *cm);

/*@}*/

#endif