/***********************************************************************************
  Filename: hal.c

  Description:  Hardware Abstraction Layer

***********************************************************************************/

#ifndef HAL_H
#define HAL_H


/***********************************************************************************
* INCLUDES
*/
#if(chip == 1110)
#include "ioCC1110.h"
#endif

#if(chip == 2510)
#include "ioCC2510.h"
#endif


/***********************************************************************************
* TYPES
*/
typedef unsigned char       BOOL;

// Data
typedef unsigned char       BYTE;
typedef unsigned short      WORD;
typedef unsigned long       DWORD;

// Unsigned numbers
typedef unsigned char       UINT8;
typedef unsigned short      UINT16;
typedef unsigned long       UINT32;

// Signed numbers
typedef signed char         INT8;
typedef signed short        INT16;
typedef signed long         INT32;


/***********************************************************************************
 * CONSTANTS
 */
#ifndef FALSE
   #define FALSE 0
#endif

#ifndef TRUE
   #define TRUE 1
#endif

#ifndef NULL
   #define NULL 0
#endif

#ifndef HIGH
   #define HIGH 1
#endif

#ifndef LOW
   #define LOW 0
#endif


/***********************************************************************************
 * MACROS
 */

#define UPPER_BYTE(a) ((BYTE) (((WORD)(a)) >> 8))
#define HIBYTE(a)     UPPER_BYTE(a)

#define LOWER_BYTE(a) ((BYTE) ( (WORD)(a))      )
#define LOBYTE(a)     LOWER_BYTE(a)

#define SET_WORD(regH, regL, word) \
   do{                             \
      (regH) = UPPER_BYTE((word)); \
      (regL) = LOWER_BYTE((word)); \
   }while(0)

#define READ_RFR16(reg)         ((((WORD) ##reg##H) << 8) + ##reg##L)
#define WRITE_RFR16(reg, value) do { ##reg##H = HIBYTE(value); ##reg##L = LOBYTE(value); } while (0)



/******************************************************************************
*******************             Port functions/macros       *******************
******************************************************************************/

// Macros for simplifying access to I/O pin setup and usage

//*****************************************************************************



// Macros for function select (General purpose I/O / Peripheral function):
// Example usage:
//   IO_FUNC_PORT0_PIN0(0, 0, IO_FUNC_PERIPH);
//   IO_FUNC_PORT0_PIN1(0, 1, IO_FUNC_GIO);
//   IO_FUNC_PORT2_PIN3(2, 3, IO_FUNC_PERIPH);

#define IO_FUNC_PORT_PIN(port, pin, func)  \
   do {                                    \
      if((port == 2) && (pin == 3)){       \
         if (func) {                       \
            P2SEL |= 0x02;                 \
         } else {                          \
            P2SEL &= ~0x02;                \
         }                                 \
      }                                    \
      else if((port == 2) && (pin == 4)){  \
         if (func) {                       \
            P2SEL |= 0x04;                 \
         } else {                          \
            P2SEL &= ~0x04;                \
         }                                 \
      }                                    \
      else{                                \
         if (func) {                       \
            P##port##SEL |= (0x01<<(pin)); \
         } else {                          \
            P##port##SEL &= ~(0x01<<(pin));\
        }                                  \
      }                                    \
   } while (0)

// where func is one of:
#define IO_FUNC_GIO     0 // General purpose I/O
#define IO_FUNC_PERIPH  1 // Peripheral function

/******************************************************************************
*******************       Interrupt functions/macros        *******************
******************************************************************************/

// Macros which simplify access to interrupt enables, interrupt flags and
// interrupt priorities. Increases code legibility.

//******************************************************************************

#define INT_ON   1
#define INT_OFF  0
#define INT_SET  1
#define INT_CLR  0

// Global interrupt enables
#define INT_GLOBAL_ENABLE(on) EA=(!!on)

#define DISABLE_ALL_INTERRUPTS() (IEN0 = IEN1 = IEN2 = 0x00)


#define INUM_RFTXRX 0
#define INUM_ADC   1
#define INUM_URX0  2
#define INUM_URX1  3
#define INUM_ENC   4
#define INUM_ST    5
#define INUM_P2INT 6
#define INUM_UTX0  7
#define INUM_DMA   8
#define INUM_T1    9
#define INUM_T2    10
#define INUM_T3    11
#define INUM_T4    12
#define INUM_P0INT 13
#define INUM_UTX1  14
#define INUM_P1INT 15
#define INUM_RF    16
#define INUM_WDT   17

#define NBR_OF_INTERRUPTS 18

// Macro used together with the INUM_* constants
// to enable or disable certain interrupts.
// Example usage:
//   INT_ENABLE(INUM_RFERR, INT_ON);
//   INT_ENABLE(INUM_URX0, INT_OFF);
//   INT_ENABLE(INUM_T1, INT_ON);
//   INT_ENABLE(INUM_T2, INT_OFF);
#define INT_ENABLE(inum, on)                        \
   do {                                             \
      if      (inum==INUM_RFTXRX) { RFTXRXIE = on; }  \
      else if (inum==INUM_ADC)   { ADCIE   = on; }  \
      else if (inum==INUM_URX0)  { URX0IE  = on; }  \
      else if (inum==INUM_URX1)  { URX1IE  = on; }  \
      else if (inum==INUM_ENC)   { ENCIE   = on; }  \
      else if (inum==INUM_ST)    { STIE    = on; }  \
      else if (inum==INUM_P2INT) { (on) ? (IEN2 |= 0x02) : (IEN2 &= ~0x02); } \
      else if (inum==INUM_UTX0)  { (on) ? (IEN2 |= 0x04) : (IEN2 &= ~0x04); } \
      else if (inum==INUM_DMA)   { DMAIE   = on; }  \
      else if (inum==INUM_T1)    { T1IE    = on; }  \
      else if (inum==INUM_T2)    { T2IE    = on; }  \
      else if (inum==INUM_T3)    { T3IE    = on; }  \
      else if (inum==INUM_T4)    { T4IE    = on; }  \
      else if (inum==INUM_P0INT) { P0IE    = on; }  \
      else if (inum==INUM_UTX1)  { (on) ? (IEN2 |= 0x08) : (IEN2 &= ~0x08); } \
      else if (inum==INUM_P1INT) { (on) ? (IEN2 |= 0x10) : (IEN2 &= ~0x10); } \
      else if (inum==INUM_RF)    { (on) ? (IEN2 |= 0x01) : (IEN2 &= ~0x01); } \
      else if (inum==INUM_WDT)   { (on) ? (IEN2 |= 0x20) : (IEN2 &= ~0x20); } \
   } while (0)



// Macro used to set or clear certain interrupt flags.
// Example usage:
//   INT_SETFLAG(INUM_URX0, INT_SET;
//   INT_SETFLAG(INUM_T3, INT_CLR);
#define INT_SETFLAG(inum, f)                     \
   do {                                          \
      if      (inum==INUM_RFTXRX){ RFTXRXIF = f; } \
      else if (inum==INUM_ADC)   { ADCIF  = f; } \
      else if (inum==INUM_URX0)  { URX0IF = f; } \
      else if (inum==INUM_URX1)  { URX1IF = f; } \
      else if (inum==INUM_ENC)   { ENCIF_1 = ENCIF_0 = f; } \
      else if (inum==INUM_ST)    { STIF  = f;  } \
      else if (inum==INUM_P2INT) { P2IF  = f;  } \
      else if (inum==INUM_UTX0)  { UTX0IF= f;  } \
      else if (inum==INUM_DMA)   { DMAIF = f;  } \
      else if (inum==INUM_T1)    { T1IF  = f;  } \
      else if (inum==INUM_T2)    { T2IF  = f;  } \
      else if (inum==INUM_T3)    { T3IF  = f;  } \
      else if (inum==INUM_T4)    { T4IF  = f;  } \
      else if (inum==INUM_P0INT) { P0IF  = f;  } \
      else if (inum==INUM_UTX1)  { UTX1IF= f;  } \
      else if (inum==INUM_P1INT) { P1IF  = f;  } \
      else if (inum==INUM_RF)    { (f) ? (S1CON |= 0x03) : (S1CON &= ~0x03); } \
      else if (inum==INUM_WDT)   { WDTIF = f;  } \
   } while (0)

/******************************************************************************
**************************   DMA structures / macros  *************************
******************************************************************************/

// The macros and structs in this section simplify setup and usage of DMA.

//******************************************************************************

#define DMA_CHANNEL_0  0x01
#define DMA_CHANNEL_1  0x02
#define DMA_CHANNEL_2  0x04
#define DMA_CHANNEL_3  0x08
#define DMA_CHANNEL_4  0x10

#define VLEN_USE_LEN            0x00 // Use LEN for transfer count
#define VLEN_FIXED              0x00 // Use LEN for transfer count
#define VLEN_1_P_VALOFFIRST     0x01 // Transfer the first byte + the number of bytes indicated by the first byte
#define VLEN_VALOFFIRST         0x02 // Transfer the number of bytes indicated by the first byte (starting with the first byte)
#define VLEN_1_P_VALOFFIRST_P_1 0x03 // Transfer the first byte + the number of bytes indicated by the first byte + 1 more byte
#define VLEN_1_P_VALOFFIRST_P_2 0x04 // Transfer the first byte + the number of bytes indicated by the first byte + 2 more bytes

#define WORDSIZE_BYTE           0x00 // Transfer a byte at a time
#define WORDSIZE_WORD           0x01 // Transfer a 16-bit word at a time

#define TMODE_SINGLE            0x00 // Transfer a single byte/word after each DMA trigger
#define TMODE_BLOCK             0x01 // Transfer block of data (length len) after each DMA trigger
#define TMODE_SINGLE_REPEATED   0x02 // Transfer single byte/word (after len transfers, rearm DMA)
#define TMODE_BLOCK_REPEATED    0x03 // Transfer block of data (after len transfers, rearm DMA)

#define DMATRIG_NONE           0   // No trigger, setting DMAREQ.DMAREQx bit starts transfer
#define DMATRIG_PREV           1   // DMA channel is triggered by completion of previous channel
#define DMATRIG_T1_CH0         2   // Timer 1, compare, channel 0
#define DMATRIG_T1_CH1         3   // Timer 1, compare, channel 1
#define DMATRIG_T1_CH2         4   // Timer 1, compare, channel 2
#define DMATRIG_T2_COMP        5   // Timer 2, compare
#define DMATRIG_T2_OVFL        6   // Timer 2, overflow
#define DMATRIG_T3_CH0         7   // Timer 3, compare, channel 0
#define DMATRIG_T3_CH1         8   // Timer 3, compare, channel 1
#define DMATRIG_T4_CH0         9   // Timer 4, compare, channel 0
#define DMATRIG_T4_CH1        10   // Timer 4, compare, channel 1
#define DMATRIG_ST            11   // Sleep Timer compare
#define DMATRIG_IOC_0         12   // Port 0 I/O pin input transition
#define DMATRIG_IOC_1         13   // Port 1 I/O pin input transition
#define DMATRIG_URX0          14   // USART0 RX complete
#define DMATRIG_UTX0          15   // USART0 TX complete
#define DMATRIG_URX1          16   // USART1 RX complete
#define DMATRIG_UTX1          17   // USART1 TX complete
#define DMATRIG_FLASH         18   // Flash data write complete
#define DMATRIG_RADIO         19   // RF packet byte received/transmit
#define DMATRIG_ADC_CHALL     20   // ADC end of a conversion in a sequence, sample ready
#define DMATRIG_ADC_CH0       21   // ADC end of conversion channel 0 in sequence, sample ready
#define DMATRIG_ADC_CH1       22   // ADC end of conversion channel 1 in sequence, sample ready
#define DMATRIG_ADC_CH2       23   // ADC end of conversion channel 2 in sequence, sample ready
#define DMATRIG_ADC_CH3       24   // ADC end of conversion channel 3 in sequence, sample ready
#define DMATRIG_ADC_CH4       25   // ADC end of conversion channel 4 in sequence, sample ready
#define DMATRIG_ADC_CH5       26   // ADC end of conversion channel 5 in sequence, sample ready
#define DMATRIG_ADC_CH6       27   // ADC end of conversion channel 6 in sequence, sample ready
#define DMATRIG_ADC_CH7       28   // ADC end of conversion channel 7 in sequence, sample ready
#define DMATRIG_ENC_DW        29   // AES encryption processor requests download input data
#define DMATRIG_ENC_UP        30   // AES encryption processor requests upload output data

#define SRCINC_0         0x00 // Increment source pointer by 0 bytes/words after each transfer
#define SRCINC_1         0x01 // Increment source pointer by 1 bytes/words after each transfer
#define SRCINC_2         0x02 // Increment source pointer by 2 bytes/words after each transfer
#define SRCINC_M1        0x03 // Decrement source pointer by 1 bytes/words after each transfer

#define DESTINC_0        0x00 // Increment destination pointer by 0 bytes/words after each transfer
#define DESTINC_1        0x01 // Increment destination pointer by 1 bytes/words after each transfer
#define DESTINC_2        0x02 // Increment destination pointer by 2 bytes/words after each transfer
#define DESTINC_M1       0x03 // Decrement destination pointer by 1 bytes/words after each transfer

#define IRQMASK_DISABLE  0x00 // Disable interrupt generation
#define IRQMASK_ENABLE   0x01 // Enable interrupt generation upon DMA channel done

#define M8_USE_8_BITS    0x00 // Use all 8 bits for transfer count
#define M8_USE_7_BITS    0x01 // Use 7 LSB for transfer count

#define PRI_LOW          0x00 // Low, CPU has priority
#define PRI_GUARANTEED   0x01 // Guaranteed, DMA at least every second try
#define PRI_HIGH         0x02 // High, DMA has priority
#define PRI_ABSOLUTE     0x03 // Highest, DMA has priority. Reserved for DMA port access.


#pragma bitfields=reversed
typedef struct {
   BYTE SRCADDRH;
   BYTE SRCADDRL;
   BYTE DESTADDRH;
   BYTE DESTADDRL;
   BYTE VLEN      : 3;
   BYTE LENH      : 5;
   BYTE LENL      : 8;
   BYTE WORDSIZE  : 1;
   BYTE TMODE     : 2;
   BYTE TRIG      : 5;
   BYTE SRCINC    : 2;
   BYTE DESTINC   : 2;
   BYTE IRQMASK   : 1;
   BYTE M8        : 1;
   BYTE PRIORITY  : 2;
} DMA_DESC;
#pragma bitfields=default


#define DMA_SET_ADDR_DESC0(a)           \
   do{                                  \
      DMA0CFGH = (BYTE)( (WORD)a >> 8 );\
      DMA0CFGL = (BYTE)( (WORD)a );     \
   } while(0)

#define DMA_SET_ADDR_DESC1234(a)        \
   do{                                  \
      DMA1CFGH = (BYTE)( (WORD)a >> 8 );\
      DMA1CFGL = (BYTE)( (WORD)a );     \
   } while(0)

#define DMA_ARM_CHANNEL(ch)           \
   do{                                \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      DMAARM = ((0x01 << ch) & 0x1F); \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
      asm("NOP");                     \
   } while(0)

#define DMA_ABORT_CHANNEL(ch)    DMAARM = (0x80 | ((0x01 << ch) & 0x1F))
#define DMA_MAN_TRIGGER(ch)      DMAREQ = (0x01 << ch)
#define DMA_START_CHANNEL(ch)    DMA_MAN_TRIGGER(ch)


// Macro for quickly setting the number of bytes to be transferred by the DMA.
// max lenght is 0x1FFF
#define SET_DMA_LENGTH(pDmaDesc, length)          \
   do{                                            \
      pDmaDesc->LENH = (BYTE) ((WORD)length >> 8);\
      pDmaDesc->LENL = (BYTE)  (WORD)length;      \
   } while (0)



// Macro for changing the pulse length of a timer in PWM mode. The value is
// not scaled and the user must verify that it is correct. _channel_ is the
// channel (1 or 2) configured for PWM operation, whereas _value_ is the
// 16 bit word giving the pulse length. This argument should be shorter than
// or equal to the value returned from the function halSetTimer1Period(...).
#define TIMER1_SET_PWM_PULSE_LENGTH(channel, value) \
   do {                                             \
      T1CC##channel##L = (BYTE)value;               \
      T1CC##channel##H = (BYTE)(value >> 8);        \
   } while(0)


// Macro for enabling or disabling overflow interrupts of timer 1.
#define TIMER1_ENABLE_OVERFLOW_INT(val) \
   (TIMIF =  (val) ? TIMIF | 0x40 : TIMIF & ~0x40)

// Macros for turning timers on or off
#define TIMER1_RUN(value)      (T1CTL = (value) ? T1CTL|0x02 : T1CTL&~0x03)
#define TIMER3_RUN(value)      (T3CTL = (value) ? T3CTL|0x10 : T3CTL&~0x10)
#define TIMER4_RUN(value)      (T4CTL = (value) ? T4CTL|0x10 : T4CTL&~0x10)


// RF interrupt flags
#define IRQ_TXUNF           0x80
#define IRQ_RXOVF           0x40
#define IRQ_TIMEOUT         0x20
#define IRQ_DONE            0x10
#define IRQ_CS              0x08
#define IRQ_PQT             0x04
#define IRQ_CCA             0x02
#define IRQ_SFD             0x01


// Radio Command Strobes
#define SFSTXON()     do{RFST = 0x00;}while(0)
#define SCAL()        do{RFST = 0x01;}while(0)
#define SRX()         do{RFST = 0x02;}while(0)
#define STX()         do{RFST = 0x03;}while(0)
#define SIDLE()       do{RFST = 0x04;}while(0)
#define SAFC()        do{RFST = 0x05;}while(0)
#define SNOP()        do{RFST = 0xFF;}while(0)



/***********************************************************************************
  Copyright 2008 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
***********************************************************************************/
#endif //HAL_H
