/**
* @file hal_cc2530znp_target_board.c
*
* @brief Hardware Abstraction Layer (HAL) for the cc2530znp target board
*
* This file must be modified if changing hardware platforms.
*
* The ZNP library & examples require the following methods to be implemented. 
* Refer to the individual method descriptions for more information.
* - halInit()
* - halSpiInitZnp()
* - delayMs()
* - toggleLed()
*
* Also see hal_cc2530znp_target_board.h for macros that must be defined.
*
* @see hal_helper.c for utilities to assist when changing hardware platforms
*
* @see http://processors.wiki.ti.com/index.php/Tutorial_on_the_Examples and http://e2e.ti.com/support/low_power_rf/default.aspx
*
* $Rev: 658 $
* $Author: dsmith $
* $Date: 2010-07-13 10:23:50 -0700 (Tue, 13 Jul 2010) $
*
* YOU 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.
*/


#include "hal_cc2530znp_target_board.h"

#ifdef __IAR_SYSTEMS_ICC__  /* IAR C Compiler */
#include "../HAL/hal_Osram_SFH5711_ambient_light_sensor.c"
#else
#include "../HAL/hal_Osram_SFH5711_ambient_light_sensor.h"
#endif 


#include "../ZNP/znp_interface_spi.h"

#define HARDWARE_UART

/* Debounce for ~5msec. */
#define DEBOUNCE_MSECS         5

/*macros for interrupt vector*/
#define _PRAGMA(x) _Pragma(#x)
#define HAL_ISR_FUNC_DECLARATION(f,v) _PRAGMA(vector=v) __interrupt void f(void)
#define HAL_ISR_FUNC_PROTOTYPE(f,v)   _PRAGMA(vector=v) __interrupt void f(void)
#define HAL_ISR_FUNCTION(f,v)        st(HAL_ISR_FUNC_PROTOTYPE(f,v); HAL_ISR_FUNC_DECLARATION(f,v)
#define INTERRUPT_TIMERA()   HAL_ISR_FUNCTION(isrTimerA, TIMERA0_VECTOR)
#define INTERRUPT_ADC10()    HAL_ISR_FUNCTION(isrADC, ADC10_VECTOR)

/* Count for ~20msec - ADC needs 17msec for refV to settle. */
#define ADC_WAIT_MSECS         20

/*Variables*/
volatile uint16 halAdcVal;
volatile uint16 halEventFlags = 0x0000;
extern unsigned char znpBuf[100];

/** Function pointer for the ISR called when the accelerometer generates an interrupt*/
void (*accelerometerIsr)(void);

/** Function pointer for the ISR called when a SRDY interrupt occurs*/
void (*srdyIsr)(void);

/** Flags to indicate when to wake up the processor. These are read in the various interrupt service routines 
and if the flag is set then the processor will be woken up with HAL_WAKEUP() at the end of the ISR. 
This is required because HAL_WAKEUP() cannot be called anywhere except in an ISR. */
unsigned int wakeupFlags = 0;

/** The post-calibrated frequency of the Very Low Oscillator (VLO). Set with calibrateVlo() and read by initTimer(). */
unsigned int vloFrequency = 0;

/**Definitions required for MT functionality  
 *Enable Compile Flag HOST_MT if using the MT Functionality
*/
#if HOST_MT
#ifdef __IAR_SYSTEMS_ICC__
	#define INTERRUPT_RX0()      HAL_ISR_FUNCTION(isrRx0, USCIAB0RX_VECTOR)
	#define INTERRUPT_TX0()      HAL_ISR_FUNCTION(isrTx0, USCIAB0TX_VECTOR)
#endif
  
  #define HOST_MT_RX_OLD 1
  #define HOST_MT_RX_FULL  (ZNP_BUF_LEN-1)  

/* Variables */
  static uint8 rx0Buf[ZNP_BUF_LEN];   
  static volatile uint8 rx0Head;
  static volatile uint8 rx0Time;
  static uint8 rx0Tail;
  static uint8 tx0Buf[ZNP_BUF_LEN];
  static uint8 tx0Head;
  static volatile uint8 tx0Tail;
#endif

/* Port 1 interrupt service routine. */
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
    if (P1IFG & BIT2)                
    { 
    /*Button Press Event*/
    P1IE  = 0;
    /*wait for 5ms*/
    halDelay(DEBOUNCE_MSECS, TRUE);
 
    #ifdef NV_RESTORE 
        /* IF NV_RESTORE is enabled and the CC2530ZNP previous NV parameters needs 
        to be cleared and CC2530ZNP and MSP430F2274 need to be Reset then press 
        the button and hold down until you see both LED's flashing
        This section tests if the button was pressed for time greater than 5 seconds 
        and sets the HAL_EVT_ZNP_RESET flag 
        */
        int wait =0; 
        do  
        {
          wait++;
          if(wait == 1000) /*for 5 seconds */
          {
           P1IFG =0;  /*clear the interrupt flag*/
           /* Set flag to Restart ZNP*/
           halEventFlags |= HAL_EVT_ZNP_RESET;  /*since timer 4 is not being used currently*/  
           __low_power_mode_off_on_exit();
           return;
          }
          halDelay(DEBOUNCE_MSECS, TRUE);  /*5ms wait*/
        }
        while((P1IN & 0x04) == 0); 
    #endif    
    /*if button was not kept presssed for more than 5 seconds*/
    P1IFG = 0;
    P1IE  = SW1_BV;
    halEventFlags |= HAL_EVT_BTN_PRESS;  /* Signal that a key press+hold event has taken place.*/
    halSwCnt++;
    __low_power_mode_off_on_exit();
    }
    if (P1IFG & BIT3)
    {
        accelerometerIsr();
        if (wakeupFlags & WAKEUP_AFTER_ACCELEROMETER)    
            HAL_WAKEUP();           
    }
    P1IFG = 0;                          /* clear the interrupt */
}

/** Port 2 interrupt service routine. */
#pragma vector=PORT2_VECTOR
__interrupt void PORT2_ISR(void)
{
  /*wake up on interrupt*/
    P2IFG = 0;                          /* clear the interrupt*/
  __low_power_mode_off_on_exit();
}    

/** 
Configures hardware for the particular hardware platform:
- Ports: sets direction, interrupts, pullup/pulldown resistors etc. 
- Oscillator: turns off WDT, configures MCLK = 8MHz using internal DCO & sets SMCLK = 4MHz
- initializes timer A
- intializes UART for MT interface to talk to Sensor monitor demo
*/
void halInit()
{
    WDTCTL = WDTPW + WDTHOLD; /* Stop WDT */
    /*    Initialize Oscillator  */
    if (CALBC1_8MHZ ==0xFF || CALDCO_8MHZ == 0xFF)                                     
    {  
        while(1); /* Stop if calibration constants erased */
    }   
    BCSCTL1 = CALBC1_8MHZ; /* Set DCO = 8MHz for MCLK */
    DCOCTL = CALDCO_8MHZ;
    BCSCTL2 |= DIVS_1;     /*SMCLK = DCO/2 (4MHz)  */
    BCSCTL3 |= LFXT1S_2;   /* Use VLO for ACLK*/
    /*    Initialize Portsv */
    /*
    PORT 1:
    1.0     LED 1
    1.1     LED 2
    1.2     Button - connects to GND when closed
    1.3     Accelerometer Interrupt
    1.4     
    1.5     
    1.6     
    1.7     
    */
    P1DIR = BIT0+BIT1; 
    P1OUT &= ~BIT2;
    P1IE  = BIT2;   /*Enable Button Interrupt*/
    P1IES = BIT2;   /*Interrupt on high-to-low transition*/
    P1REN = BIT2;   /*enable resistor for button*/
    P1OUT = BIT2;   /*make resistor a PULL-UP*/
    P1SEL = 0;      /*NOTE: default value is NOT 0!*/
    P1IFG = 0;
    /*PORT 2
    2.0     
    2.1     Light Sensor power
    2.2     TEST
    2.3     
    2.4     
    2.5     
    2.6     SRDY
    2.7     Accelerometer SS
    */
    P2OUT = 0xDD;  /*Light sensor is turned down*/
    P2DIR = 0xBE;
    P2SEL = 0;
    /* Configure the SRDY for ISR on active low so that slave does not timeout awaiting the RPC
    * handshake sequence and reset.
    */
    P2REN = BV(6);  /*Pull up for SRDY Line (Input to MSP)*/
    halConfigureSrdyInterrrupt(SRDY_INTERRUPT_FALLING_EDGE); 
    P2IFG = 0;  /*clear the interrupt flag*/
    ENABLE_SRDY_INTERRUPT(); /*P2IE  = BV(6);*/
    /*PORT 3
    3.0     ZNP CS
    3.1     SPI MOSI
    3.2     SPI MISO
    3.3     SPI SCLK
    3.4     Debug UART Tx
    3.5     Debug UART Rx
    3.6     MRDY
    3.7     ZNP Reset
    */
    P3OUT = 0x7F;
    P3DIR = 0xE0;
    P3SEL = (BIT1+BIT2+BIT3+BIT4+BIT5);  /*p3.1,2,3=USCI_B0; P3.4,5 = USCI_A0 TXD/RXD;*/
    /*PORT 4
    4.0     CFG 0
    4.1     CFG 1
    4.2     CC2530 programming DC
    4.3     CC2530 programming DD
    4.4     
    4.5     
    4.6     
    4.7     
    */
    P4OUT = 0xE3;
    P4DIR = 0xF3;
    P4SEL = 0;
    /* Deselect SPI peripherals:*/
    SPI_SS_CLEAR();                       /* Deselect ZNP*/
    ACCELEROMETER_SS_CLEAR();             /* Deselect acceleration sensor */
    /*  Stop Timer A:*/
    TACTL = MC_0;                       
    clearLeds();
    /*initialize Timer A for state machine operation */
    halTimerInit();  /* Initilize Timer*/
}

/** Configures SRDY interrupt. Does NOT enable the interrupt.
On the CC2530 target board, SRDY is P2.6
@param flags the options for the SRDY interrupt: 
- SRDY_INTERRUPT_FALLING_EDGE or SRDY_INTERRUPT_RISING_EDGE
- NO_WAKEUP or WAKEUP_AFTER_SRDY
@return 0 if success, -1 if bad flag
*/
signed int halConfigureSrdyInterrrupt(unsigned char flags)
{
    if (flags & (~(SRDY_INTERRUPT_FALLING_EDGE | WAKEUP_AFTER_SRDY)))   /*if any other bit is set in flags */
        return -1;                                                      /*then error*/
    
    if (flags & SRDY_INTERRUPT_FALLING_EDGE)
        P2IES |= BIT6;      /*Interrupt on high-to-low transition*/
    else
        P2IES &= ~BIT6;     /*Interrupt on low-to-high transition  */      
    
    if (flags & WAKEUP_AFTER_SRDY)
        wakeupFlags |= WAKEUP_AFTER_SRDY;
    else
        wakeupFlags &= ~WAKEUP_AFTER_SRDY;
    return 0;
}

/**
Initializes the Serial Peripheral Interface (SPI) interface to the Zigbee Network Processor (ZNP).
@note Maximum CC2530ZNP SPI clock speed is 4MHz. SPI port configured for clock polarity of 0, clock phase of 0, and MSB first.
@note On the CC2530ZNP target board the MSP430 uses USCIB0 SPI port to communicate with the ZNP
@pre SPI pins configured correctly: Clock, MOSI, MISO configured as SPI function; Chip Select configured as an output; SRDY configured as an input.
@post SPI port is configured for ZNP communications.
*/
void halSpiInitZnp()
{
    UCB0CTL1 |= UCSSEL_2 | UCSWRST;                 /*serial clock source = SMCLK, hold SPI interface in reset*/
    UCB0CTL0 = UCCKPH | UCMSB | UCMST | UCSYNC;     /*clock polarity = inactive is LOW (CPOL=0); Clock Phase = 0; MSB first; Master Mode; Synchronous Mode    */
    UCB0BR0 = 2;  UCB0BR1 = 0;                      /*SPI running at 2MHz (SMCLK / 2)*/
    UCB0CTL1 &= ~UCSWRST;                           /*start USCI_B1 state machine  */
}

/**
Sends a message over SPI to the ZNP. Based on hal_board.c in CC2480 example application ZASA.
The ZNP uses a "write-to-read" approach: to read data out, you must write data in.
This is a private method that gets wrapped by other methods, e.g. spiSreq(), spiAreq, etc.
To Write, set *bytes and numBytes. To Read, set *bytes only. Don't need to set numBytes because CC2530ZNP will stop when no more bytes are received.
@param bytes the data to be sent or received.
@param numBytes the number of bytes to be sent. This same buffer will be overwritten with the received data.
@pre SPI port configured for the ZNP
@pre CC2530ZNP has been initialized
@post bytes contains received data, if any
*/
void spiWrite(unsigned char *bytes, unsigned char numBytes)
{
    while (numBytes--)
    {  
        UCB0TXBUF = *bytes;
        while (!(IFG2 & UCB0RXIFG)) ;     /*WAIT for a character to be received, if any*/
        *bytes++ = UCB0RXBUF;             /*read bytes*/
    }
}

/**
* Blocking Delay in Milliseconds
* delays by at least the specified number of milliseconds (ms)
* @pre TICKS_PER_MS set
* @param ms number of milliseconds to delay
*/
void delayMs(unsigned int ms)    
{
    unsigned int a, b;
    for (a = ms; a > 0; a--)         /* outer loop takes 5 ck per round  */
        for (b = TICKS_PER_MS; b > 0; b--)  /* inner loop takes 5 ck per round */
#ifdef __IAR_SYSTEMS_ICC__  /* IAR C Compiler */
         	asm("nop"); 
#else
			asm(" nop");
#endif 
 
}

/** Blocking Delay in Microseconds
delays by at least the specified number of microseconds (us)
@pre TICKS_PER_US set
@param us number of microseconds to delay
*/
void delayUs(unsigned int us)
{
    unsigned int a; 
    us *= TICKS_PER_US; 
    for (a = us; a > 0; a--)  /* loop takes 5 ck per round */        
	{
        asm ("nop"); 
	}
}

/* halDelay Delay for milliseconds.
Do not invoke with zero.
Do not invoke with greater than 500 msecs.
Invoking with very high frequency and/or with long delays will start to
significantly impact the real time performance of TimerA tasks because this will
invisibly overrun the period when the TimerA count remaining, when this function
is invoked, is less than the delay requested.
input parameters msecs - Milliseconds to delay in low power mode, sleep - Enforces blocking delay in low power mode if set.
output parameters None. @return None.
*/
void halDelay(uint8 msecs, uint8 sleep)
{
  /* Expected scaling for msecs is 3/2, but depends on result of TimerA calibration.*/
  /* TBD - not enough code space: uint16 stop = msecs * (TACCR0_INIT / 10) / (1000 / 10);*/
  uint16 stop = msecs * 3 / 2;

  HAL_DISABLE_INTERRUPTS();  
   TACTL &= ~MC_1;  /* Stop the timer.*/

  if (TAR != TACCR0_INIT)
  {
    stop += TAR;
    if (stop == TACCR0_INIT)
    {
      stop++;
    }
  }
  TACCR0 = stop;

  TACTL |= MC_1;  /* Re-start the timer.*/
  HAL_ENABLE_INTERRUPTS();   

  if (sleep)
  {
    do {
      HAL_SLEEP();
    } while (TACCR0 != TACCR0_INIT);
  }
}

/** Turns ON the specified LED. 
@param led the LED to turn on, must be 0 or 1.
@post The specified LED is turned on. 
@return 0 if success, -1 if invalid LED specified
*/
signed int setLed(unsigned char led)
{
    if (led > 1) 
        return -1;
    P1OUT |= (led) ? BIT1 : BIT0;
    return 0;
}

/** Turns OFF LEDs. 
@post LEDs are turned off. 
*/
void clearLeds()
{
    P1OUT &= ~(BIT0 + BIT1);
}

/** Toggles the specified LED. 
@param led the LED to toggle, must be 0 or 1.
@post The specified LED is toggled. 
@return 0 if success, -1 if invalid LED specified
*/
signed int toggleLed(unsigned char led)
{
    if (led > 1) 
        return -1;
    P1OUT ^= (1 << led);
    return 0;
}

/* CC2530ZNP Target Board Peripherals Not Reqyuired for ZNP Operations */

/** Reads the MSP430 supply voltage using the Analog to Digital Converter (ADC). 
On CC2530ZNP target board, this is approx. 3600mV
@return Vcc supply voltage, in millivolts
*/
unsigned int getVcc3()
{
    ADC10CTL0 = SREF_1 + REFON + REF2_5V + ADC10ON + ADC10SHT_3;  /* use internal ref, turn on 2.5V ref, set samp time = 64 cycles */
    ADC10CTL1 = INCH_11;                         
    delayMs(1);                                     /* Allow internal reference to stabilize*/
    ADC10CTL0 |= ENC + ADC10SC;                     /* Enable conversions*/
    while (!(ADC10CTL0 & ADC10IFG));                /* Conversion done?*/
    unsigned long temp = (ADC10MEM * 5000l);        /* Convert raw ADC value to millivolts*/
    return ((unsigned int) (temp / 1024l));
}

/** Reads the light sensor.
Turns on Light sensor, configures ADC, reads the value, and converts it to lux.
@note Light sensor outputs current between 0 to 50uA. On the target board, load resistor = 47k Ohms.
@note 0 to 100,000lx will generate 0 to 2350mV input into our ADC.
@note Light sensor analog input is on P2.0, or analog input A0.
@note This light sensor is binned for a sensitivity of 27 to 30 uA @ 1000lux = 1269-1410 mV = ADC readings of 520-578counts 
@return Light Sensor reading in lux/10.
*/
unsigned int getLightSensor()
{
    LIGHT_SENSOR_ON();
    ADC10AE0 = 0x01;
    ADC10CTL0 = SREF_1 + REFON + REF2_5V + ADC10ON + ADC10SHT_3;  /* use internal ref, turn on 2.5V ref, set samp time = 64 cycles*/
    ADC10CTL1 = INCH_0;                             /* Analog input A0*/
    delayMs(1);                                     /* Allow internal reference to stabilize, also light sensor needs time to stabilize*/
    ADC10CTL0 |= ENC + ADC10SC;                     /* Enable conversions*/
    while (!(ADC10CTL0 & ADC10IFG));                /* Conversion done?*/
    LIGHT_SENSOR_OFF();
    return (convertAdcToLux(ADC10MEM));
}


/* Only Required for Target Board */

/** Initializes the SPI port for the Accelerometer.
Required because accelerometer SPI port uses different settings than the ZNP SPI port
*/
void halSpiInitAccelerometer()
{
    UCB0CTL1 |= UCSSEL_2 | UCSWRST;                 /*serial clock source = SMCLK, hold SPI interface in reset. NOTE: SMCLK is 4MHz*/
    UCB0CTL0 = UCCKPH | UCMSB | UCMST | UCSYNC;     /*clock polarity = inactive is LOW (CPOL=0); Clock Phase = 0; MSB first; Master Mode; Synchronous Mode    */
    UCB0BR0 = 16;  UCB0BR1 = 0;                     /*SPI running at 250kHz (SMCLK / 16)*/
    UCB0CTL1 &= ~UCSWRST;                           /*start USCI_B1 state machine */
    wakeupFlags |= WAKEUP_AFTER_ACCELEROMETER;
}

/** Enables the interrupt on the accelerometer (P1.3). 
@param wakeOnAccelerometer whether to wakeup after this int is triggered. Must be either NO_WAKEUP or WAKEUP_AFTER_ACCELEROMETER.
@return 0 if success; -1 if invalid wakeOnAccelerometer parameter
*/
signed int halEnableAccelerometerInterrupt(unsigned char wakeOnAccelerometer)
{
    if ((wakeOnAccelerometer != NO_WAKEUP) && (wakeOnAccelerometer != WAKEUP_AFTER_ACCELEROMETER))
        return -1;       
    P1IE |= BIT3;
    P1IES &= ~BIT3;  /*Generate interrupt on Low to High Edge*/
    P1IFG = 0;
    return 0;
}

/* Simple utility method used in accelerometer methods. 
@param b the byte to write
*/
unsigned char spiWriteAccelerometer(unsigned char b)
{
    UCB0TXBUF = b;                            /* Write address to TX buffer */
    while (!(IFG2 & UCB0RXIFG)) ;             /* Wait until new data was written into RX buffer */
    return(UCB0RXBUF);                        /* Read RX buffer just to clear interrupt flag      */
}

/** Configures all ZNP interface signals as inputs to allow the ZNP to be programmed.
Toggles LED0 quickly to indicate application is running. 
*/
void setZnpInterfaceToInputs(void)
{
    WDTCTL = WDTPW + WDTHOLD; /* Stop WDT*/
    if (CALBC1_8MHZ ==0xFF || CALDCO_8MHZ == 0xFF)                                     
    {  
        while(1); /* Stop if calibration constants erased*/
    }   
    BCSCTL1 = CALBC1_8MHZ; /* Set DCO = 8MHz for MCLK*/
    DCOCTL = CALDCO_8MHZ;
    BCSCTL2 |= DIVS_1;     /*SMCLK = DCO/2 (4MHz)    */
    
    P1DIR = 1; P1REN = 0; P1IE = 0; P1SEL = 0; 
    P2DIR = 0; P2REN = 0; P2IE = 0; P2SEL = 0; 
    P3DIR = 0;
    P4DIR = 0; P4REN = 0; P4SEL = 0;   
    for (;;)
    {
        toggleLed(0);
        delayMs(100);   
    }
}

/** Calibrate VLO. Once this is done, the VLO can be used semi-accurately for timers etc. 
Once calibrated, VLO is within ~2% of actual when using a 1% calibrated DCO frequency and temperature and supply voltage remain unchanged.
@return VLO frequency (number of VLO counts in 1sec), or -1 if out of range
@pre SMCLK is 4MHz
@pre MCLK is 8MHz
@pre ACLK sourced by VLO (BCSCTL3 = LFXT1S_2; in MSP430F2xxx)
@note Calibration is only as good as MCLK source. Obviously, if using the internal DCO (+/- 1%) then this value will only be as good as +/- 1%. YMMV.
@note On MSP430F248 or MSP430F22x2 or MSP430F22x4, must use TACCR2. On MSP430F20x2, must use TACCR0.
Check device-specific datasheet to see which module block has ACLK as a compare input.
For example, see page 23 of the MSP430F24x datasheet or page 17 of the MSP430F20x2 datasheet, or page 18 of the MSP430F22x4 datasheet.
@note If application will require accuracy over change in temperature or supply voltage, recommend calibrating VLO more often.
@post Timer A settings changed
@post ACLK divide by 8 bit cleared
*/
signed int calibrateVlo()
{
    WDTCTL = WDTPW + WDTHOLD;             /* Stop watchdog timer*/
    delayMs(1000);
    
    BCSCTL1 |= DIVA_3;                    /* Divide ACLK by 8*/
    TACCTL2 = CM_1 + CCIS_1 + CAP;        /* Capture on ACLK*/
    TACTL = TASSEL_2 + MC_2 + TACLR;      /* Start TA, SMCLK(DCO), Continuous*/
    while ((TACCTL0 & CCIFG) == 0);       /* Wait until capture*/
    
    TACCR2 = 0;                           /* Ignore first capture*/
    TACCTL2 &= ~CCIFG;                    /* Clear CCIFG*/
    
    while ((TACCTL2 & CCIFG) == 0);       /* Wait for next capture*/
    unsigned int firstCapture = TACCR2;   /* Save first capture*/
    TACCTL2 &= ~CCIFG;                    /* Clear CCIFG*/
    
    while ((TACCTL2 & CCIFG) ==0);        /* Wait for next capture*/
    
    unsigned long counts = (TACCR2 - firstCapture);        /* # of VLO clocks in 8Mhz*/
    BCSCTL1 &= ~DIVA_3;                   /* Clear ACLK/8 settings*/
    
    vloFrequency = ((unsigned int) (32000000l / counts));
    if ((vloFrequency > VLO_MIN) && (vloFrequency < VLO_MAX))
        return vloFrequency;
    else
        return -1;
}

/* halReadTemp This function starts the ADC and sets up to read the channel for temperature.
input parameters None. output parameters None. @return None.
*/
void halReadTemp(void)
{
  /* Setup code taken from eZ430-RF2500 Temperature Sensor End Device.*/
  ADC10CTL1 = INCH_10 + ADC10DIV_4;       /* Temp Sensor ADC10CLK/5*/
  ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ADC10SR;
  halDelay(ADC_WAIT_MSECS, TRUE);         /* Allow Vref to ADC to charge.*/
  ADC10CTL0 |= ENC | ADC10SC;             /* Sampling and conversion start*/
}

/* halReadBusV This function sets up to read the channel for bus voltage.
input parameters None. output parameters None. @return None.
*/
void halReadBusV(void)
{
  /* Setup code taken from TI example code: msp430x22x4_adc11_temp.c.*/
  ADC10CTL1 = INCH_11 + ADC10DIV_3; /* Internal bus voltage, ADC10CLK/4*/
  ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE;
  halDelay(ADC_WAIT_MSECS, TRUE);         /* Allow Vref to ADC to charge.*/
  ADC10CTL0 |= ENC | ADC10SC;             /* Sampling and conversion start*/
}

/* halTimerInit : initialize timer A for 1 sec interval (to work from VLO for low powr modes)
input parameters None. output parameters None.  @return None.
*/
static void halTimerInit(void)
{
  uint16 loop = 62;  /* Count 4mHz by 65536 timer overflow.*/

  /*if coming from a PUC after button press reset
  - Timer module may remain unaffected
  - Stop Timer A and B by writing zero to TACCR0 and TBCCR0.
  */
  TACCR0 = 0; /*Stop Timer A*/
  TBCCR0 = 0; /*Stop Timer B*/
    
  
  BCSCTL1 |= DIVA_3;               /* ACLK/8*/
  BCSCTL3 |= LFXT1S_2;             /* ACLK = VLO*/

  /* Setup TimerB to calibrate TimerA.*/
  TBCCR0 = 65535;

  /* Setup TimerA to be calibrated.*/
  TACCR0 = 65535;
  TACTL = TASSEL_1 + MC_1;         /* ACLK, up count mode.*/

  /* Calibrate TimerA.*/
  TBCTL = TBSSEL_2 + MC_1;         /* SMCLK, up count mode.*/

  do {
    while ((TBCTL & TBIFG) == 0);
    TBCTL &= ~TBIFG;
  } while (--loop);
  TBCTL = TBCLR;  /* Clear TimerB configuration.*/

  TACTL &= ~MC_1;  /* Stop TimerA.*/
  TACCR0_INIT = TAR;
  TACTL |= MC_1;  /* Resume TimerA.*/

  /* Configure TimerA for 1-msec ISR for driving the HAL S/W timers, timing key press+hold, etc.*/
  TACCR0 = TACCR0_INIT;            
  //TACTL = TASSEL_1 + MC_1;          //ACLK, up count mode.*/
  TACCTL0 = CCIE;                  /* TACCR0 interrupt enabled*/
}

/*halTimerSet This function sets the timer period and control flags as specified.
input parameters tIdx - HAL Timer index, period - Timer period in msecs (zero to turn off.),
ctlFlags - Bit mask of timer control flags. output parameters None.@return None.
 */
void halTimerSet(uint8 tIdx, uint16 period, uint8 ctlFlags)
{
  halIntState_t s;

  if (ctlFlags & HAL_TIMER_AUTO)
  {
    tmrPeriod[tIdx] = period;
  }
  else
  {
    tmrPeriod[tIdx] = 0;
  }

  HAL_ENTER_CRITICAL_SECTION(s);
  tmrTicks[tIdx] = period;
  halEventFlags &= ~BV(tIdx);
  HAL_EXIT_CRITICAL_SECTION(s);
}

/* isrTimerA This function services the Timer-A interrupt.
input parameters None. output parameters None.@return None.
*/
#ifdef __IAR_SYSTEMS_ICC__
	INTERRUPT_TIMERA()
#else 
	#pragma vector=TIMERA0_VECTOR
	__interrupt void isrTimerA(void)
#endif
{
  uint8 idx;

  if (TACCR0 != TACCR0_INIT)
  {
    __low_power_mode_off_on_exit();

    if (TACCR0 < TACCR0_INIT)
    {
      TACCR0 = TACCR0_INIT;
      return;
    }
    TAR = 0;
    TACCR0 = TACCR0_INIT;
  }

#if HOST_MT
  if (rx0Time != 0)
  {
    /* If an Rx byte is waiting.*/
    if (rx0Time >= HOST_MT_RX_OLD)
    {
      halEventFlags |= HAL_EVT_MT_RX_RDY;
      rx0Time = 0;
    }
    else
    {
      rx0Time++;
    }
  }
#endif
  /* Update all active S/W timers.*/
  for (idx = 0; idx < HAL_TIMER_CNT; idx++)
  {
    if ((tmrTicks[idx] != 0) && (--tmrTicks[idx] == 0))
    {
      tmrTicks[idx] = tmrPeriod[idx];
      halEventFlags |= BV(idx);
    }
  }
  if (halEventFlags != 0)
  {
    __low_power_mode_off_on_exit();
  }
}

/*isrADC This function services the ADC interrupt.input parameters None.
output parameters None. @return None.
*/
#ifdef __IAR_SYSTEMS_ICC__
INTERRUPT_ADC10()
#else
#pragma vector=ADC10_VECTOR
__interrupt void isrADC(void)
#endif
{
  halAdcVal = ADC10MEM;
  halEventFlags |= HAL_EVT_ADC;  /* Signal that the ADC sample is ready.*/
  ADC10CTL0 = 0;                 /* Disable the ADC*/
  ADC10CTL0 = 0;                 /* Turn off reference (must be done AFTER clearing ENC).*/
  
  __low_power_mode_off_on_exit();
}

#if HOST_MT
/* halUARTRead This function blocks transfers the bytes read by ISR to the parameter buffer.
input parameters - port - HAL_PORT_NUM to read, pBuf - Pointer to the buffer to copy up to len bytes of Rx,
len - Max number of bytes to copy into pBuf. Output parameters pBuf - Pointer to the buffer that gets filled with the Rx bytes.
@return Number of bytes actually copied into pBuf.
*/
uint8 halUARTRead(uint8 port, uint8 *pBuf, uint8 len)
{
  uint8 cnt = 0;
  uint8 x=0;
  if (port == HAL_PORT_MT)
  {
    while (len--)
    {
      if (rx0Tail == rx0Head)
      {
        break;
      }
      znpBuf[x] = rx0Buf[rx0Tail];
      x++;
      if (rx0Tail == 0)
      {
        rx0Tail = ZNP_BUF_LEN-1;
      }
      else
      {
        rx0Tail--;
      }
      cnt++;
    }
  }
  return cnt;
}
/* halUARTWrite This function sets up the UART Tx buffer to transmit by ISR.
input parameters - port - HAL_PORT_NUM to write, pBuf - Pointer to the buffer that contains the data to transmit,
len - Length of the data to transmit.output parameters None.@return None.
*/
void halUARTWrite(uint8 port, uint8 *pBuf, uint8 len)
{
  if (port == HAL_PORT_MT)
  {
    while (len--)
    {
      tx0Buf[tx0Head] = *pBuf++;
      if (tx0Head == 0)
      {
        tx0Head = ZNP_BUF_LEN-1;
      }
      else
      {
        tx0Head--;
      }
    }
    IE2 |= UCA0TXIE;  /* Enable UART Tx ISR. */
    
  }
}
/*UART ISRs These ISRs handle Rx/Tx on UART0.input parameters None. 
output parameters None. @return None.
 */
#ifdef __IAR_SYSTEMS_ICC__
INTERRUPT_RX0()
#else
#pragma vector=USCIAB0RX_VECTOR 
__interrupt void isrRx0(void)
#endif
{  
  /*this function keeps adding the UART recieved data into rx0BUF and decrementing the tmp varaible*/
  uint8 tmp = rx0Head;
  rx0Buf[tmp] = UCA0RXBUF;
  if (tmp == 0)
  {
    tmp = ZNP_BUF_LEN-1;
  }
  else
  {
    tmp--;
  }
  rx0Head = tmp;
  tmp = rx0Tail - tmp;
#if ZNP_BUF_LEN != 256
  if (tmp > ZNP_BUF_LEN)
  {
    tmp += ZNP_BUF_LEN;
  }
#endif
  if (tmp >= HOST_MT_RX_FULL-1)
  {
    halEventFlags |= HAL_EVT_MT_RX_RDY;
  }
  else
  {
    rx0Time = 1;
  }
}

#ifdef __IAR_SYSTEMS_ICC__
INTERRUPT_TX0()
#else
#pragma vector=USCIAB0TX_VECTOR 
__interrupt void isrTx0(void)
#endif
{
  if (tx0Tail != tx0Head)
  {
    while (!(IFG2 & UCA0TXIFG));   /* Wait for ready */
    UCA0TXBUF = tx0Buf[tx0Tail];
    if (tx0Tail == 0)
    {
      tx0Tail = ZNP_BUF_LEN-1;
    }
    else
    {
      tx0Tail--;
    }
  }
  else
  {
    IE2 &= ~UCA0TXIE;  /* Disable interrupt. */
  }
}
#endif
