/*******************************************************************************
*
* Freescale Semiconductor Inc.
* (c) Copyright 2004-2007 Freescale Semiconductor, Inc.
* ALL RIGHTS RESERVED.
*
********************************************************************************
*
* File Name:  mscan.h
*
* $Date:      Oct-12-2010$
*
* $Version:   2.3.11.0$
*
* Description: Header file for the msCAN driver
*
*******************************************************************************/

#ifndef __MSCAN_H
#define __MSCAN_H

/* qs.h is a master header file, which must be included */
#if !defined(__ARCH_H) || !defined(__PERIPH_H) || !defined(__APPCONFIG_H)
#error Please include qs.h before mscan.h
#endif

#ifdef __cplusplus
extern "C" {
#endif

/******************************************************************************
*
*                      General Interface Description
*
* The module is a communication controller, implementing the CAN 2.0A/B protocol 
* as defined in the Bosch specification dated September 1991. Though not exclusively 
* intended for automotive applications, CAN protocol is designed to meet specific
* requirements of a vehicle serial data bus, that is real-time processing, reliable 
* operation in the EMI environment of a vehicle, cost-effectiveness, and required 
* bandwidth. CAN uses an advanced buffer arrangement resulting in predictable real-
* time behavior and simplified application software.
*
******************************************************************************/

/************************************************************
* MSCAN module identifiers
*************************************************************/

#define MSCAN (&ArchIO.MSCan)

#define MSCAN_RB (&ArchIO.MSCan.canrb)
#define MSCAN_TB (&ArchIO.MSCan.cantb)

typedef arch_sMSCAN_MB MSCAN_MB;

/*************************************************************
* arch.h should define device-specific information about MSCAN
**************************************************************/

#if !defined(MSCAN_VERSION)
#error MSCAN not properly described in arch.h
#endif

/****************************************************
* Configurable items, i.e. defines for appconfig.h
*****************************************************

  #define INTC_VECTOR_ADDR_yy     interrupt vector (e.g. mscanISR)
  #define INTC_PRIORITY_LEVEL_yy  one of INTC_DISABLED, INTC_LEVEL0, INTC_LEVEL1 or INTC_LEVEL2
    where yy is interrupt number  (e.g. interrupts 20..23 are used by msCAN on 56F8037)

    MSCAN_CANCTL0_INIT 
    MSCAN_CANCTL1_INIT 
    MSCAN_CANBTR0_INIT 
    MSCAN_CANBTR1_INIT 
    MSCAN_CANIDAC_INIT 
    MSCAN_CANIDARn_INIT n=0..7
    MSCAN_CANIDMRn_INIT n=0..7

*/

/*****************************************************************
* Single-Instruction  ioctl() commands
*
*  Word16 ioctl( MSCAN_module_identifier, Command_name, Parameter );
*
******************************************************************

        COMMAND NAME                      PARAMETERS, COMMENTS
------------------------------------------------------------------ */

/* init-only commands (CAN must be in reset) */
#define MSCAN_DEVICE                /* Enable/disable the MSCAN peripheral; MSCAN_ENABLE/MSCAN_DISABLE */
#define MSCAN_WAKEUP_FILTER         /* Enable/disable low-pass filter on wake-up condition; MSCAN_ENABLE/MSCAN_DISABLE */
#define MSCAN_MANUAL_BOFF_RECOVERY  /* Enable/disable manual bus-off recovery mode; MSCAN_ENABLE/MSCAN_DISABLE */
#define MSCAN_LISTEN_ONLY_MODE      /* Enable/disable listen only mode; MSCAN_ENABLE/MSCAN_DISABLE */
#define MSCAN_LOOPBACK_MODE         /* Enable/disable test loopback mode; MSCAN_ENABLE/MSCAN_DISABLE */
#define MSCAN_SET_CLOCK_SOURCE      /* select clock source; MSCAN_IPBUS / MSCAN_XTAL */

#define MSCAN_SET_SAMPLING          /* set samples per bit; MSCAN_1SAMP_PER_BIT, MSCAN_3SAMPS_PER_BIT,  */

#define MSCAN_SET_ACC_MASKR_8_0     /* set 8bit acceptance mask 0; value for mask registers */
#define MSCAN_SET_ACC_MASKR_8_1     /* set 8bit acceptance mask 1; value for mask registers */
#define MSCAN_SET_ACC_MASKR_8_2     /* set 8bit acceptance mask 2; value for mask registers */
#define MSCAN_SET_ACC_MASKR_8_3     /* set 8bit acceptance mask 3; value for mask registers */
#define MSCAN_SET_ACC_MASKR_8_4     /* set 8bit acceptance mask 4; value for mask registers */
#define MSCAN_SET_ACC_MASKR_8_5     /* set 8bit acceptance mask 5; value for mask registers */
#define MSCAN_SET_ACC_MASKR_8_6     /* set 8bit acceptance mask 6; value for mask registers */
#define MSCAN_SET_ACC_MASKR_8_7     /* set 8bit acceptance mask 7; value for mask registers */

#define MSCAN_SET_ACC_IDR_8_0       /* set 8bit acceptance id 0; value for IDR registers */
#define MSCAN_SET_ACC_IDR_8_1       /* set 8bit acceptance id 1; value for IDR registers */
#define MSCAN_SET_ACC_IDR_8_2       /* set 8bit acceptance id 2; value for IDR registers */
#define MSCAN_SET_ACC_IDR_8_3       /* set 8bit acceptance id 3; value for IDR registers */
#define MSCAN_SET_ACC_IDR_8_4       /* set 8bit acceptance id 4; value for IDR registers */
#define MSCAN_SET_ACC_IDR_8_5       /* set 8bit acceptance id 5; value for IDR registers */
#define MSCAN_SET_ACC_IDR_8_6       /* set 8bit acceptance id 6; value for IDR registers */
#define MSCAN_SET_ACC_IDR_8_7       /* set 8bit acceptance id 7; value for IDR registers */

/* run-time commands */
#define MSCAN_AUTO_WAKEUP           /* Enable automatic wakeup, MSCAN_ENABLE/MSCAN_DISABLE */
#define MSCAN_TIMESTAMP_TIMER       /* Enable timestamp timer, MSCAN_ENABLE/MSCAN_DISABLE */
#define MSCAN_CLEAR_RXFRM           /* Clear frame-received flag, NULL */
#define MSCAN_STOP_IN_WAIT          /* Enable low-power in wait mode; MSCAN_ENABLE/MSCAN_DISABLE */
#define MSCAN_ERINT_ENABLE          /* Enable Error & Receiver Interrupt; Interrupts switches (see bellow) */
#define MSCAN_ERINT_DISABLE         /* Disable Error & Receiver Interrupt; Interrupts switches (see bellow) */

#define MSCAN_TINT_ENABLE           /* Enable Tx Interrupt; Interrupts switches (see bellow) */
#define MSCAN_TINT_DISABLE          /* Disable Tx Interrupt; Interrupts switches (see bellow) */
#define MSCAN_GET_ENABLED_TINT      /* Return Enabled Tx Interrupts; NULL */
#define MSCAN_READ_TINT_FLAGS       /* Get Transmitter Interrupt status (all TXEn bits); NULL */
#define MSCAN_CLEAR_ERINT_FLAGS     /* Clear RX & Error interrupt flags, Bits to clear (obtained from MSCAN_READ_ERINT_FLAGS) */
#define MSCAN_CLEAR_EINT_FLAGS      /* Clear Error interrupt flags, Bits to clear (obtained from MSCAN_READ_EINT_FLAGS) */
#define MSCAN_CLEAR_RINT_FLAG       /* Clear Receiver-full interrupt flag, NULL */
#define MSCAN_CLEAR_WINT_FLAG       /* Clear Wakeup interrupt flag, NULL */

#define MSCAN_TRANSMIT              /* Send selected Tx buffers (Clear Transmitter interrupt flag); Bit obtained from MSCAN_SELECT_NEXT_TXBUFF */
#define MSCAN_ABORT_TRANSMIT        /* Abort transmission in selected Tx buffers; MSCAN_TXBUFFERx bits */
#define MSCAN_READ_ABORT_ACK        /* Read abort acknowledge bits; NULL */

#define MSCAN_RECOVER_BUSOFF_STATE  /* Recover from bus-off state, NULL */

#define MSCAN_GET_RX_ERR_COUNT      /* read RX error counter; NULL */
#define MSCAN_GET_TX_ERR_COUNT      /* read TX error counter; NULL */

/****************************************************
 * ioctl commands for MB modules
 ***************************************************/
#define MSCANMB_GET_LEN     /* Get Data Length Register of given MB; NULL */
#define MSCANMB_GET_DATAPTR /* Get Pointer to 8 data registers for MB; NULL */

#define MSCANMB_SET_LEN     /* Set length field of the MB; length */
#define MSCANMB_SET_TBP     /* Set Transmit Buffer Priority of given MB; priority */


/*****************************************************************
* Multi-Instruction ioctl() commands
*
*  Word16 ioctl( INTC_module_identifier, Command_name, Parameter );
*
******************************************************************

        COMMAND NAME                      PARAMETERS, COMMENTS
------------------------------------------------------------------ */

/* init-only commands (CAN must be in reset) */
#define MSCAN_SET_PRESCALER         /* set BRP; number 1, .. 64 */
#define MSCAN_SET_SJW               /* set SJW; number MSCAN_SJW_1, .. MSCAN_SJW_4 or number 1..4 */
#define MSCAN_SET_TSEG1             /* set TSEG1; number MSCAN_TSEG_1, .. MSCAN_TSEG_16 or number 1..16 */
#define MSCAN_SET_TSEG2             /* set TSEG1; number MSCAN_TSEG_1, .. MSCAN_TSEG_8  or number 1..8 */
#define MSCAN_SET_ACC_MODE          /* set acceptance mode; MSCAN_ACC_MODE_2X32, ... */

#define MSCAN_SET_ACC_MASKR_32_0    /* set 32bit acceptance mask 0; value for mask registers */
#define MSCAN_SET_ACC_MASKR_32_1    /* set 32bit acceptance mask 1; value for mask registers */
#define MSCAN_SET_ACC_MASKR_16_0    /* set 16bit acceptance mask 0; value for mask registers */
#define MSCAN_SET_ACC_MASKR_16_1    /* set 16bit acceptance mask 1; value for mask registers */
#define MSCAN_SET_ACC_MASKR_16_2    /* set 16bit acceptance mask 2; value for mask registers */
#define MSCAN_SET_ACC_MASKR_16_3    /* set 16bit acceptance mask 3; value for mask registers */

#define MSCAN_SET_ACC_IDR_32_0      /* set 32bit acceptance id 0; value for IDR registers */
#define MSCAN_SET_ACC_IDR_32_1      /* set 32bit acceptance id 1; value for IDR registers */
#define MSCAN_SET_ACC_IDR_16_0      /* set 16bit acceptance id 0; value for IDR registers */
#define MSCAN_SET_ACC_IDR_16_1      /* set 16bit acceptance id 1; value for IDR registers */
#define MSCAN_SET_ACC_IDR_16_2      /* set 16bit acceptance id 2; value for IDR registers */
#define MSCAN_SET_ACC_IDR_16_3      /* set 16bit acceptance id 3; value for IDR registers */

/* run-time commands */
#define MSCAN_TEST_SYNCH            /* Test bus-off/on condition, NULL */
#define MSCAN_TEST_RXACT            /* Test receiver activity, NULL */
#define MSCAN_TEST_RXFRM            /* Test frame-received flag, NULL */
#define MSCAN_ERINT_SET_RSTATE_MODE /* Set CSC interrupt source for receiver; one of MSCAN_STAT_xxx */
#define MSCAN_ERINT_SET_TSTATE_MODE /* Set CSC interrupt source for transmitter; one of MSCAN_STAT_xxx */
#define MSCAN_SELECT_TXBUFF         /* selects given txbuff; returns 0 when buffer is not available; specify MSCAN_TXBUFFERx mask */
#define MSCAN_SELECT_NEXT_TXBUFF    /* finds an empty TX Buffer, selects it into addrss space and returns its bit; returns 0 when no buffer is available */
#define MSCAN_READ_ERINT_FLAGS      /* Get RX & Error Interrupt status ; NULL */
#define MSCAN_READ_EINT_FLAGS       /* Get Error Interrupt status; NULL */

#define MSCAN_TEST_BUSOFF_HOLD      /* Test if bus-off state is waiting for manual recovery, NULL */
#define MSCAN_GET_WINNING_ACC_FILTER /* for currently received frame, return index of the fitler being hit, NULL */

/****************************************************
 * ioctl commands for MB modules
 ***************************************************/
#define MSCANMB_GET_ID      /* Get translated ID; NULL */
#define MSCANMB_GET_ID_RAW  /* Get four IDR registers of MB as a single 32 bit word; NULL */
#define MSCANMB_GET_RTR     /* Return non-zero if RTR is set in given MB; NULL */
#define MSCANMB_GET_TIMESTAMP  /* Get Timestamp value; NULL */

#define MSCANMB_SET_ID      /* Set ID; 32bit value, use MSCAN_ID_EXT and MSCAN_ID_RTR */
#define MSCANMB_SET_ID_V    /* Same as above, implemented as function */
#define MSCANMB_SET_ID_RAW  /* Set four IDR registers from a single 32 bit word; 32bit value */
#define MSCANMB_SET_RTR     /* Set/Clear RTR bits in given MB; MSCAN_ON/MSCAN_OFF */


/*****************************************************************
* Software Layer ioctl() commands
*
*  Word16 ioctl( INTC_module_identifier, Command_name, Parameter );
*
******************************************************************

 COMMAND NAME                         PARAMETERS, COMMENTS
----------------------------------------------------------------*/
#define MSCAN_INIT                  /* MSCAN peripheral initialization, NULL */

#define MSCAN_SOFT_RESET            /* Enter/leave soft-reset state, MSCAN_ON/MSCAN_OFF*/

/* run-time commands */
#define MSCAN_SLEEP                 /* Enter/leave sleeping state, MSCAN_ON/MSCAN_OFF */
#define MSCAN_WAIT_SLEEP            /* Wait until sleep mode is entered, NULL */
#define MSCAN_GET_SLEEP_MODE        /* Returns the sleeping state MSCAN_SLEEPING, ..., NULL */


/****************************************************************************
* MSCAN constants and type declarations used in the ioctl commands
*****************************************************************************/

#define MSCAN_ENABLE    1
#define MSCAN_DISABLE   0

#define MSCAN_ON        1
#define MSCAN_OFF       0

/* Clock selection */
#define MSCAN_IPBUS     1
#define MSCAN_XTAL      0

/* sleep status */
#define MSCAN_NOT_SLEEPING     0
#define MSCAN_SLEEPING         1
#define MSCAN_SLEEP_REQUESTED  2

/* Acceptance modes */
#define MSCAN_ACC_MODE_2X32   MSCAN_CANIDAC_IDAM_2X32
#define MSCAN_ACC_MODE_4X16   MSCAN_CANIDAC_IDAM_4X16
#define MSCAN_ACC_MODE_8X8    MSCAN_CANIDAC_IDAM_8X8
#define MSCAN_ACC_MODE_CLOSED MSCAN_CANIDAC_IDAM_CLOSED

/* Sampling mode */
#define MSCAN_1SAMP_PER_BIT   0
#define MSCAN_3SAMPS_PER_BIT  1

/* SJW vlaues */
#define MSCAN_SJW_1    1
#define MSCAN_SJW_2    2
#define MSCAN_SJW_3    3
#define MSCAN_SJW_4    4

/* Time Segment values */
#define MSCAN_TSEG_1   1
#define MSCAN_TSEG_2   2
#define MSCAN_TSEG_3   3
#define MSCAN_TSEG_4   4
#define MSCAN_TSEG_5   5
#define MSCAN_TSEG_6   6
#define MSCAN_TSEG_7   7
#define MSCAN_TSEG_8   8
#define MSCAN_TSEG_9   9
#define MSCAN_TSEG_10  10
#define MSCAN_TSEG_11  11
#define MSCAN_TSEG_12  12
#define MSCAN_TSEG_13  13
#define MSCAN_TSEG_14  14
#define MSCAN_TSEG_15  15
#define MSCAN_TSEG_16  16

/* Receiver and Error interrupts & status bits */
#define MSCAN_WAKEUP_INT   MSCAN_CANRIER_WUPIE
#define MSCAN_STATCHNG_INT MSCAN_CANRIER_CSCIE
#define MSCAN_OVERRUN_INT  MSCAN_CANRIER_OVRIE
#define MSCAN_RXFULL_INT   MSCAN_CANRIER_RXFIE

#define MSCAN_STAT_VOID    0
#define MSCAN_STAT_BUSOFF  1
#define MSCAN_STAT_ERR     2
#define MSCAN_STAT_ALL     3

/* Transmitter interrupts */
#define MSCAN_TXEMPTY0_INT     MSCAN_CANTCR_TXEIE0
#define MSCAN_TXEMPTY1_INT     MSCAN_CANTCR_TXEIE1
#define MSCAN_TXEMPTY2_INT     MSCAN_CANTCR_TXEIE2
#define MSCAN_TXEMPTY_ALL_INTS (MSCAN_TXEMPTY0 | MSCAN_TXEMPTY1 | MSCAN_TXEMPTY2)

/* Transmit buffers */
#define MSCAN_TXBUFFER0    MSCAN_CANTCR_TXEIE0
#define MSCAN_TXBUFFER1    MSCAN_CANTCR_TXEIE1
#define MSCAN_TXBUFFER2    MSCAN_CANTCR_TXEIE2
#define MSCAN_ANY_TXBUFFER (MSCAN_TXBUFFER0 | MSCAN_TXBUFFER1 | MSCAN_TXBUFFER2)
#define MSCAN_ALL_TXBUFFERS MSCAN_ANY_TXBUFFER

/* special flags for passing the ID value */
#define MSCAN_ID_EXT  0x80000000 /* specifies extended ID anywhere the ID is required */
#define MSCAN_ID_RTR  0x40000000 /* turns on the RTR bit when calling MSCANMB_SET_ID (only) */

/* special bits withing 32-bit IDRAW value */
#define MSCAN_IDR_SRTR 0x00100000
#define MSCAN_IDR_IDE  0x00080000
#define MSCAN_IDR_ERTR 0x00000001

/****************************************************************************
* MSCAN constants for backward compatibility with 56F800 and MPC5200 drivers
*****************************************************************************/

#define MSCAN_WAKEUP       MSCAN_WAKEUP_INT  
#define MSCAN_STATCHNG     MSCAN_STATCHNG_INT
#define MSCAN_OVERRUN      MSCAN_OVERRUN_INT 
#define MSCAN_RXFULL       MSCAN_RXFULL_INT  

#define MSCAN_TXEMPTY0     MSCAN_TXEMPTY0_INT
#define MSCAN_TXEMPTY1     MSCAN_TXEMPTY1_INT   
#define MSCAN_TXEMPTY2     MSCAN_TXEMPTY2_INT   
#define MSCAN_TXEMPTY_ALL  MSCAN_TXEMPTY_ALL_INTS

/****************************************************************************
* MSCAN register bit names
*****************************************************************************/

/* CANCTL0 */
#define MSCAN_CANCTL0_INITRQ        0x0001
#define MSCAN_CANCTL0_SFTRES        0x0001   /* old name of INITRQ bit */
#define MSCAN_CANCTL0_SLPRQ         0x0002
#define MSCAN_CANCTL0_WUPE          0x0004
#define MSCAN_CANCTL0_TIME          0x0008
#define MSCAN_CANCTL0_SYNCH         0x0010
#define MSCAN_CANCTL0_CSWAI         0x0020
#define MSCAN_CANCTL0_RXACT         0x0040
#define MSCAN_CANCTL0_RXFRM         0x0080

/* CANCTL1 */
#define MSCAN_CANCTL1_INITAK        0x0001
#define MSCAN_CANCTL1_SLPAK         0x0002
#define MSCAN_CANCTL1_WUPM          0x0004
#define MSCAN_CANCTL1_BORM          0x0008
#define MSCAN_CANCTL1_LISTEN        0x0010
#define MSCAN_CANCTL1_LOOPB         0x0020
#define MSCAN_CANCTL1_CLKSRC        0x0040
#define MSCAN_CANCTL1_CANE          0x0080

/* CANBTR0 */
#define MSCAN_CANBTR0_SJW_MASK      0x00c0
#define MSCAN_CANBTR0_BRP_MASK      0x003f

/* CANBTR1 */
#define MSCAN_CANBTR1_SAMP          0x0080
#define MSCAN_CANBTR1_TSEG2_MASK    0x0070
#define MSCAN_CANBTR1_TSEG1_MASK    0x000f

/* CANRFLG */
#define MSCAN_CANRFLG_WUPIF         0x80
#define MSCAN_CANRFLG_CSCIF         0x40
#define MSCAN_CANRFLG_RSTAT_MASK    0x30
#define MSCAN_CANRFLG_TSTAT_MASK    0x0c
#define MSCAN_CANRFLG_OVRIF         0x02
#define MSCAN_CANRFLG_RXF           0x01

#define MSCAN_CANRFLG_IF_MASK       0xc3
#define MSCAN_CANRFLG_EIF_MASK      0x42

/* CANRIER */
#define MSCAN_CANRIER_WUPIE         0x80
#define MSCAN_CANRIER_CSCIE         0x40
#define MSCAN_CANRFLG_RSTATE_VOID   0x00
#define MSCAN_CANRFLG_RSTATE_RXWARN 0x10
#define MSCAN_CANRFLG_RSTATE_RXERR  0x20
#define MSCAN_CANRFLG_RSTATE_ALL    0x30
#define MSCAN_CANRFLG_RSTATE_MASK   0x30
#define MSCAN_CANRFLG_TSTATE_VOID   0x00
#define MSCAN_CANRFLG_TSTATE_TXWARN 0x04
#define MSCAN_CANRFLG_TSTATE_TXERR  0x08
#define MSCAN_CANRFLG_TSTATE_ALL    0x0c
#define MSCAN_CANRFLG_TSTATE_MASK   0x0c
#define MSCAN_CANRIER_OVRIE         0x02
#define MSCAN_CANRIER_RXFIE         0x01
#define MSCAN_CANRIER_IE_MASK       0xc3

/* CANTFLG */
#define MSCAN_CANTFLG_TXE0          0x0001
#define MSCAN_CANTFLG_TXE1          0x0002
#define MSCAN_CANTFLG_TXE2          0x0004
#define MSCAN_CANTFLG_ABTAK0        0x0010
#define MSCAN_CANTFLG_ABTAK1        0x0020
#define MSCAN_CANTFLG_ABTAK2        0x0040
#define MSCAN_CANTFLG_TXEF_MASK     0x0007

/* CANTCR */
#define MSCAN_CANTCR_TXEIE0         0x0001
#define MSCAN_CANTCR_TXEIE1         0x0002
#define MSCAN_CANTCR_TXEIE2         0x0004
#define MSCAN_CANTCR_ABTRQ0         0x0010
#define MSCAN_CANTCR_ABTRQ1         0x0020
#define MSCAN_CANTCR_ABTRQ2         0x0040
#define MSCAN_CANTCR_IE_MASK        0x0007

/* CANIDAC */
#define MSCAN_CANIDAC_IDAM_MASK     0x0030
#define MSCAN_CANIDAC_IDAM_2X32     0x0000
#define MSCAN_CANIDAC_IDAM_4X16     0x0010
#define MSCAN_CANIDAC_IDAM_8X8      0x0020
#define MSCAN_CANIDAC_IDAM_CLOSED   0x0030
#define MSCAN_CANIDAC_IDHIT2        0x0004
#define MSCAN_CANIDAC_IDHIT1        0x0002
#define MSCAN_CANIDAC_IDHIT0        0x0001
#define MSCAN_CANIDAC_IDHIT_MASK    0x0007

/* MB */

#define MSCAN_MB_IDR1_SRTR 0x0010
#define MSCAN_MB_IDR1_IDE  0x0008
#define MSCAN_MB_IDR3_ERTR 0x0001

/***********************************************************************
* MSCAN inline functions
***********************************************************************/

/* ID to IDR */
inline UWord32 MSCAN_Id2Idr(UWord32 id)
{
    /* Extended ID ? */
    if(id & 0x80000000)
        return (((id & 0x1FFC0000L) << 3) | 0x00180000L | ((id & 0x0003FFFFL) << 1));
    /* Standard ID ! */
    else
        return id << 21;
}

/* IDR to ID */
inline UWord32 MSCAN_Idr2Id(UWord32 idr)
{
    /* Extended ID ? */
    if(idr & 0x80000L)
        return ((idr >> 1) & 0x3FFFFL) | ((idr >> 3) & 0x1FFC0000) | 0x80000000;
    /* Standard ID ! */
    else
        return idr >> 21;
}

/* same as above but implemented as a function call (use when passing a variable) */
UWord32 MSCAN_Id2Idr_V(register UWord32 id);
UWord32 MSCAN_Idr2Id_V(register UWord32 idr);

/***********************************************************************
* MSCAN control command macros
***********************************************************************/

/* MSCAN initialization */

void mscanInit(arch_sMSCAN *pCanBase);
#define ioctlMSCAN_INIT(pCanBase, param) mscanInit(pCanBase)

/* MSCAN Control Register 0 */

#define ioctlMSCAN_SOFT_RESET(pCanBase, param) \
  if (param) { periphBitSet(MSCAN_CANCTL0_INITRQ, &(pCanBase)->canctl0); \
               while(!periphBitTest(MSCAN_CANCTL1_INITAK, (&(pCanBase)->canctl1))) { } } \
  else periphBitClear(MSCAN_CANCTL0_INITRQ, &(pCanBase)->canctl0)

#define ioctlMSCAN_SLEEP(pCanBase, param) \
  if (param) { periphBitSet(MSCAN_CANCTL0_SLPRQ, &(pCanBase)->canctl0); \
               while(!periphBitTest(MSCAN_CANCTL1_SLPAK, (&(pCanBase)->canctl1))) { } } \
  else periphBitClear(MSCAN_CANCTL0_SLPRQ, &(pCanBase)->canctl0)

#define ioctlMSCAN_WAIT_SLEEP(pCanBase, param) \
    while(!periphBitTest(MSCAN_CANCTL1_SLPAK, (&(pCanBase)->canctl1))) { }

#define ioctlMSCAN_GET_SLEEP_MODE(pCanBase, param) \
  ((UWord16)((periphBitTest(MSCAN_CANCTL1_SLPAK, &(pCanBase)->canctl1) ? MSCAN_SLEEPING : \
             (periphBitTest(MSCAN_CANCTL0_SLPRQ, &(pCanBase)->canctl0) ? MSCAN_SLEEP_REQUESTED : \
                                                                        MSCAN_NOT_SLEEPING))))

#define ioctlMSCAN_AUTO_WAKEUP(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANCTL0_WUPE, &(pCanBase)->canctl0); \
  else periphBitClear(MSCAN_CANCTL0_WUPE, &(pCanBase)->canctl0)

#define ioctlMSCAN_TIMESTAMP_TIMER(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANCTL0_TIME, &(pCanBase)->canctl0); \
  else periphBitClear(MSCAN_CANCTL0_TIME, &(pCanBase)->canctl0)

#define ioctlMSCAN_TEST_SYNCH(pCanBase, param) \
  periphBitTest(MSCAN_CANCTL0_SYNCH, &(pCanBase)->canctl0)

#define ioctlMSCAN_STOP_IN_WAIT(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANCTL0_CSWAI, &(pCanBase)->canctl0); \
  else periphBitClear(MSCAN_CANCTL0_CSWAI, &(pCanBase)->canctl0)

#define ioctlMSCAN_TEST_RXACT(pCanBase, param) \
  periphBitTest(MSCAN_CANCTL0_RXACT, &(pCanBase)->canctl0)
  
#define ioctlMSCAN_TEST_RXFRM(pCanBase, param) \
  periphBitTest(MSCAN_CANCTL0_RXFRM, &(pCanBase)->canctl0)
  
#define ioctlMSCAN_CLEAR_RXFRM(pCanBase, param) \
  periphBitSet(MSCAN_CANCTL0_RXFRM, &(pCanBase)->canctl0)
  
/* MSCAN Control Register 1 */

#define ioctlMSCAN_WAKEUP_FILTER(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANCTL1_WUPM, &(pCanBase)->canctl1); \
  else periphBitClear(MSCAN_CANCTL1_WUPM, &(pCanBase)->canctl1)
  
#define ioctlMSCAN_MANUAL_BOFF_RECOVERY(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANCTL1_BORM, &(pCanBase)->canctl1); \
  else periphBitClear(MSCAN_CANCTL1_BORM, &(pCanBase)->canctl1)

#define ioctlMSCAN_LISTEN_ONLY_MODE(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANCTL1_LISTEN, &(pCanBase)->canctl1); \
  else periphBitClear(MSCAN_CANCTL1_LISTEN, &(pCanBase)->canctl1)

#define ioctlMSCAN_LOOPBACK_MODE(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANCTL1_LOOPB, &(pCanBase)->canctl1); \
  else periphBitClear(MSCAN_CANCTL1_LOOPB, &(pCanBase)->canctl1)

#define ioctlMSCAN_SET_CLOCK_SOURCE(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANCTL1_CLKSRC, &(pCanBase)->canctl1); \
  else periphBitClear(MSCAN_CANCTL1_CLKSRC, &(pCanBase)->canctl1)
 
#define ioctlMSCAN_DEVICE(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANCTL1_CANE, &(pCanBase)->canctl1); \
  else periphBitClear(MSCAN_CANCTL1_CANE, &(pCanBase)->canctl1)

/* Bus Timing Register 0 */

#define ioctlMSCAN_SET_PRESCALER(pCanBase, param) \
  periphBitGrpRS(MSCAN_CANBTR0_BRP_MASK, (param)-1, &(pCanBase)->canbtr0)

#define ioctlMSCAN_SET_SJW(pCanBase, param) \
  periphBitGrpRS(MSCAN_CANBTR0_SJW_MASK, ((param)-1) << 6, &(pCanBase)->canbtr0)

/* Bus Timing Register 0 */

#define ioctlMSCAN_SET_TSEG1(pCanBase, param) \
  periphBitGrpRS(MSCAN_CANBTR1_TSEG1_MASK, (param)-1, &(pCanBase)->canbtr1)

#define ioctlMSCAN_SET_TSEG2(pCanBase, param) \
  periphBitGrpRS(MSCAN_CANBTR1_TSEG2_MASK, ((param)-1) << 4, &(pCanBase)->canbtr1)

#define ioctlMSCAN_SET_SAMPLING(pCanBase, param) \
  if (param) periphBitSet(MSCAN_CANBTR1_SAMP, &(pCanBase)->canbtr1); \
  else periphBitClear(MSCAN_CANBTR1_SAMP, &(pCanBase)->canbtr1)

/* Receiver Interrupt Enable Register */

#define ioctlMSCAN_ERINT_ENABLE(pCanBase, param)    \
  periphBitSet((param) & MSCAN_CANRIER_IE_MASK, &(pCanBase)->canrier)
  
#define ioctlMSCAN_ERINT_DISABLE(pCanBase, param) \
  periphBitClear((param) & MSCAN_CANRIER_IE_MASK, &(pCanBase)->canrier)
  
#define ioctlMSCAN_ERINT_SET_RSTATE_MODE(pCanBase, param) \
  periphBitGrpRS(MSCAN_CANRFLG_RSTATE_MASK, (param) << 4, &(pCanBase)->canrier)
  
#define ioctlMSCAN_ERINT_SET_TSTATE_MODE(pCanBase, param) \
  periphBitGrpRS(MSCAN_CANRFLG_TSTATE_MASK, (param) << 2, &(pCanBase)->canrier)

/* Receiver Interrupt Flag Register */
  
#define ioctlMSCAN_CLEAR_ERINT_FLAGS(pCanBase, param)   \
  periphMemWrite((param) & MSCAN_CANRFLG_IF_MASK, &(pCanBase)->canrflg)

#define ioctlMSCAN_READ_ERINT_FLAGS(pCanBase, param)    \
  periphBitTest(MSCAN_CANRFLG_IF_MASK, &(pCanBase)->canrflg)
  
#define ioctlMSCAN_CLEAR_EINT_FLAGS(pCanBase, param)   \
  periphMemWrite((param) & MSCAN_CANRFLG_EIF_MASK, &(pCanBase)->canrflg)

#define ioctlMSCAN_READ_EINT_FLAGS(pCanBase, param)    \
  periphBitTest(MSCAN_CANRFLG_EIF_MASK, &(pCanBase)->canrflg)

#define ioctlMSCAN_CLEAR_RINT_FLAG(pCanBase, param)   \
  periphMemWrite(MSCAN_CANRFLG_RXF, &(pCanBase)->canrflg)

#define ioctlMSCAN_CLEAR_WINT_FLAG(pCanBase, param)   \
  periphMemWrite(MSCAN_CANRFLG_WUPIF, &(pCanBase)->canrflg)
  
/* Transmitter Interrupt Enable Register */
  
#define ioctlMSCAN_TINT_ENABLE(pCanBase, param)     \
  periphBitSet((param) & MSCAN_CANTCR_IE_MASK, &(pCanBase)->cantcr)

#define ioctlMSCAN_TINT_DISABLE(pCanBase, param)    \
  periphBitClear((param) & MSCAN_CANTCR_IE_MASK, &(pCanBase)->cantcr)

#define ioctlMSCAN_GET_ENABLED_TINT(pCanBase, param)    \
  periphMemRead(&(pCanBase)->cantcr)

/* Transmitter Interrupt Flag Register */
  
#define ioctlMSCAN_READ_TINT_FLAGS(pCanBase, param)     \
  periphMemRead(&(pCanBase)->cantflg)

#define ioctlMSCAN_TRANSMIT(pCanBase, param)    \
  periphMemWrite(param, &(pCanBase)->cantflg)

/* Transmitter Message Abort Request Register */

#define ioctlMSCAN_ABORT_TRANSMIT(pCanBase, param)  \
  periphMemWrite(param, &(pCanBase)->cantarq)

/* Transmitter Message Abort Acknowledge Register */

#define ioctlMSCAN_READ_ABORT_ACK(pCanBase, param)  \
  periphMemWrite(param, &(pCanBase)->cantaak)

/* Transmit Buffer Selection Register */

#define ioctlMSCAN_SELECT_TXBUFF(pCanBase, param)   \
  (periphMemWrite((param) & periphMemRead(&(pCanBase)->cantflg), &(pCanBase)->cantbsel), \
   (UWord16) ((param) & periphMemRead(&(pCanBase)->cantbsel) & periphMemRead(&(pCanBase)->cantflg)))

#define ioctlMSCAN_SELECT_NEXT_TXBUFF(pCanBase, param)  \
  (periphMemWrite(periphMemRead(&(pCanBase)->cantflg), &(pCanBase)->cantbsel), \
   periphMemRead(&(pCanBase)->cantbsel) & periphMemRead(&(pCanBase)->cantflg))

/* Miscellanous Register */

/* Test if bus-off state is waiting for manual recovery, NULL */
#define ioctlMSCAN_TEST_BUSOFF_HOLD(pCanBase, param)  \
    periphBitTest(MSCAN_MISC_BOHOLD, &(pCanBase)->canmisc)

/* Recover from bus-off state, NULL */
#define ioctlMSCAN_RECOVER_BUSOFF_STATE(pCanBase, param)  \
    periphMemWrite(MSCAN_MISC_BOHOLD, &(pCanBase)->canmisc)
    

/* Identifier Acceptance Control Register */

#define ioctlMSCAN_SET_ACC_MODE(pCanBase, param) \
  periphBitGrpRS(MSCAN_CANIDAC_IDAM_MASK, param, &(pCanBase)->canidac)

#define ioctlMSCAN_GET_WINNING_ACC_FILTER(pCanBase, param) \
  periphBitTest(MSCAN_CANIDAC_IDHIT_MASK, &(pCanBase)->canidac)


/* set 32bit acceptance mask 0 */
#define ioctlMSCAN_SET_ACC_MASKR_32_0(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr3); \
    periphMemWrite((UWord16)((param) >> 16), &(pCanBase)->canidmr1); \
    periphMemWrite((UWord16)((param) >>  8), &(pCanBase)->canidmr2); \
    periphMemWrite((UWord16)((param) >> 24), &(pCanBase)->canidmr0); \
  }

/* set 32bit acceptance mask 1 */
#define ioctlMSCAN_SET_ACC_MASKR_32_1(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr7); \
    periphMemWrite((UWord16)((param) >> 16), &(pCanBase)->canidmr5); \
    periphMemWrite((UWord16)((param) >>  8), &(pCanBase)->canidmr6); \
    periphMemWrite((UWord16)((param) >> 24), &(pCanBase)->canidmr4); \
  }

/* set 16bit acceptance mask 0 */
#define ioctlMSCAN_SET_ACC_MASKR_16_0(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr1); \
    periphMemWrite((UWord16)((param) >> 8), &(pCanBase)->canidmr0); \
  }

/* set 16bit acceptance mask 1 */
#define ioctlMSCAN_SET_ACC_MASKR_16_1(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr3); \
    periphMemWrite((UWord16)((param) >> 8), &(pCanBase)->canidmr2); \
  }

/* set 16bit acceptance mask 2 */
#define ioctlMSCAN_SET_ACC_MASKR_16_2(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr5); \
    periphMemWrite((UWord16)((param) >> 8), &(pCanBase)->canidmr4); \
  }

/* set 16bit acceptance mask 3 */
#define ioctlMSCAN_SET_ACC_MASKR_16_3(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr7); \
    periphMemWrite((UWord16)((param) >> 8), &(pCanBase)->canidmr6); \
  }

/* set 8bit acceptance mask 0 */
#define ioctlMSCAN_SET_ACC_MASKR_8_0(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr0)

/* set 8bit acceptance mask 1 */
#define ioctlMSCAN_SET_ACC_MASKR_8_1(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr1)

/* set 8bit acceptance mask 2 */
#define ioctlMSCAN_SET_ACC_MASKR_8_2(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr2)

/* set 8bit acceptance mask 3 */
#define ioctlMSCAN_SET_ACC_MASKR_8_3(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr3)

/* set 8bit acceptance mask 4 */
#define ioctlMSCAN_SET_ACC_MASKR_8_4(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr4)

/* set 8bit acceptance mask 5 */
#define ioctlMSCAN_SET_ACC_MASKR_8_5(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr5)

/* set 8bit acceptance mask 6 */
#define ioctlMSCAN_SET_ACC_MASKR_8_6(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr6)

/* set 8bit acceptance mask 7 */
#define ioctlMSCAN_SET_ACC_MASKR_8_7(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidmr7)

/* set 32bit acceptance mask 0 */
#define ioctlMSCAN_SET_ACC_IDR_32_0(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar3); \
    periphMemWrite((UWord16)((param) >> 16), &(pCanBase)->canidar1); \
    periphMemWrite((UWord16)((param) >>  8), &(pCanBase)->canidar2); \
    periphMemWrite((UWord16)((param) >> 24), &(pCanBase)->canidar0); \
  }

/* set 32bit acceptance mask 1 */
#define ioctlMSCAN_SET_ACC_IDR_32_1(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar7); \
    periphMemWrite((UWord16)((param) >> 16), &(pCanBase)->canidar5); \
    periphMemWrite((UWord16)((param) >>  8), &(pCanBase)->canidar6); \
    periphMemWrite((UWord16)((param) >> 24), &(pCanBase)->canidar4); \
  }

/* set 16bit acceptance mask 0 */
#define ioctlMSCAN_SET_ACC_IDR_16_0(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar1); \
    periphMemWrite((UWord16)((param) >> 8), &(pCanBase)->canidar0); \
  }

/* set 16bit acceptance mask 1 */
#define ioctlMSCAN_SET_ACC_IDR_16_1(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar3); \
    periphMemWrite((UWord16)((param) >> 8), &(pCanBase)->canidar2); \
  }

/* set 16bit acceptance mask 2 */
#define ioctlMSCAN_SET_ACC_IDR_16_2(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar5); \
    periphMemWrite((UWord16)((param) >> 8), &(pCanBase)->canidar4); \
  }

/* set 16bit acceptance mask 3 */
#define ioctlMSCAN_SET_ACC_IDR_16_3(pCanBase, param)  { \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar7); \
    periphMemWrite((UWord16)((param) >> 8), &(pCanBase)->canidar6); \
  }

/* set 8bit acceptance mask 0 */
#define ioctlMSCAN_SET_ACC_IDR_8_0(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar0)

/* set 8bit acceptance mask 1 */
#define ioctlMSCAN_SET_ACC_IDR_8_1(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar1)

/* set 8bit acceptance mask 2 */
#define ioctlMSCAN_SET_ACC_IDR_8_2(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar2)

/* set 8bit acceptance mask 3 */
#define ioctlMSCAN_SET_ACC_IDR_8_3(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar3)

/* set 8bit acceptance mask 4 */
#define ioctlMSCAN_SET_ACC_IDR_8_4(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar4)

/* set 8bit acceptance mask 5 */
#define ioctlMSCAN_SET_ACC_IDR_8_5(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar5)

/* set 8bit acceptance mask 6 */
#define ioctlMSCAN_SET_ACC_IDR_8_6(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar6)

/* set 8bit acceptance mask 7 */
#define ioctlMSCAN_SET_ACC_IDR_8_7(pCanBase, param) \
    periphMemWrite((UWord16)(param), &(pCanBase)->canidar7)


/* Receive Error Counter Register */

#define ioctlMSCAN_GET_RX_ERR_COUNT(pCanBase, param) \
    periphMemRead((&(pCanBase)->canrxerr))

/* Transmit Error Counter Register */

#define ioctlMSCAN_GET_TX_ERR_COUNT(pCanBase, param) \
    periphMemRead((&(pCanBase)->cantxerr))

/***************************
* Message Buffer commands 
****************************/

/* Get translated ID */
UWord32 ioctlMSCANMB_GET_ID(arch_sMSCAN_MB* pMSCanMB, void*);

/* Get four IDR registers of given MB as a single 32 bit word */
/* unused bits are reset to 0 */
inline UWord32 ioctlMSCANMB_GET_ID_RAW(arch_sMSCAN_MB* pMSCanMB, void*)
{
    register UWord16* pidr = (UWord16*) &pMSCanMB->idr0;
    register UWord32 ret;

    asm { 
        .iasm_reg2regsetcopyflag on

        move.w X:(pidr+0),A1
        move.w X:(pidr+2),A0
        asll.l #8,A
        move.w X:(pidr+1),B1
        move.w X:(pidr+3),B0
        or.l B,A
        brset #8,A1,Finish
        bfclr #7,A1
        clr.w A0
        
        .iasm_reg2regsetcopyflag off
        
Finish:
        tfr A,ret
    }
    
    return ret;
}

/* Get length field of the MB; NULL */
#define ioctlMSCANMB_GET_LEN(pMSCanMB, param) \
    periphMemRead((&(pMSCanMB)->dlr))

/* Return non-zero if RTR is set in given MB; NULL */
#define ioctlMSCANMB_GET_RTR(pMSCanMB, param) \
    ( periphBitTest(MSCAN_MB_IDR1_IDE,  &(pMSCanMB)->idr1) ? \
        periphBitTest(MSCAN_MB_IDR3_ERTR,  &(pMSCanMB)->idr3) : \
        periphBitTest(MSCAN_MB_IDR1_SRTR,  &(pMSCanMB)->idr1) )\
    
#define ioctlMSCANMB_GET_DATAPTR(pMSCanMB, param) \
    ((UWord16*)(&(pMSCanMB)->dsr0))

/* Get timestamp field of the MB; NULL */
#define ioctlMSCANMB_GET_TIMESTAMP(pMSCanMB, param) \
    ((UWord16)((periphMemRead(&(pMSCanMB)->tsrh) << 8) | \
               (periphMemRead(&(pMSCanMB)->tsrl) & 0xff)))


/* Set Data Length Register for given MB; len */
#define ioctlMSCANMB_SET_LEN(pMSCanMB, param) \
    periphMemWrite(param, (&(pMSCanMB)->dlr))

/* Set Transmit Buffer Priority for given MB; ; priority */
#define ioctlMSCANMB_SET_TBP(pMSCanMB, param) \
    periphMemWrite(param, (&(pMSCanMB)->tbpr))

/* Set four IDR registers of given MB using a single 32 bit word */
inline void ioctlMSCANMB_SET_ID_RAW(arch_sMSCAN_MB* pMSCanMB, register UWord32 idr)
{
    register UWord16* pidr = (UWord16*) &pMSCanMB->idr0;
    
    asm {
        tfr idr,A
        
        .iasm_reg2regsetcopyflag off
        
        move.w A1,X:(pidr+1)
        move.w A0,X:(pidr+3)
        lsrr.l #8,A
        move.w A1,X:(pidr+0)
        move.w A0,X:(pidr+2)
        
        .iasm_reg2regsetcopyflag on
    }
}

inline void ioctlMSCANMB_SET_ID(arch_sMSCAN_MB* pMSCanMB, register UWord32 id)
{
    /* Note: we use inline function because mostly the ID is specified as constant so
          the ID->IDR conversion is done by preprocessor and code is really optimal */
   
    register UWord32 idr = MSCAN_Id2Idr(id);

    /* set RTR ? */
    if(id & MSCAN_ID_RTR)
        idr |= MSCAN_MB_IDR3_ERTR | (((UWord32)MSCAN_MB_IDR1_SRTR) << 16);
                
    /* store into MB (can't use move.l due to misalignment) */
    ioctl(pMSCanMB, MSCANMB_SET_ID_RAW, idr);   
}

/* same as above but done as function (to be used when ID passed is a variable) */
void ioctlMSCANMB_SET_ID_V(register arch_sMSCAN_MB* pMSCanMB, register UWord32 id);

/* Write given ID to the apropriate bits in given MB; MSCAN_ON/MSCAN_OFF */
#define ioctlMSCANMB_SET_RTR(pMSCanMB, param) \
  if(param) { \
    periphBitSet(MSCAN_MB_IDR1_SRTR,  &(pMSCanMB)->idr1); \
    periphBitSet(MSCAN_MB_IDR3_ERTR,  &(pMSCanMB)->idr3); \
  } \
  else \
  { \
    if(periphBitTest(MSCAN_MB_IDR1_IDE,  &(pMSCanMB)->idr1)) \
      periphBitClear(MSCAN_MB_IDR3_ERTR,  &(pMSCanMB)->idr3); \
    else \
      periphBitClear(MSCAN_MB_IDR1_SRTR,  &(pMSCanMB)->idr1); \
  }


#ifdef __cplusplus
}
#endif

#endif                                      
