#include  "msp430g2231.h"
#define     LED1                  BIT0
#define     LED2                  BIT6
#define     LED_DIR               P1DIR
#define     LED_OUT               P1OUT
#define     BUTTON                BIT3
#define     BUTTON_OUT            P1OUT
#define     BUTTON_DIR            P1DIR
#define     BUTTON_IN             P1IN
#define     BUTTON_IE             P1IE
#define     BUTTON_IES            P1IES
#define     BUTTON_IFG            P1IFG
#define     BUTTON_REN            P1REN
#define     TXD                   BIT1                      
#define     RXD                   BIT2                      
#define     APP_STANDBY_MODE      0
#define     APP_APPLICATION_MODE  1
#define     TIMER_PWM_MODE        0   
#define     TIMER_UART_MODE       1
#define     TIMER_PWM_PERIOD      2000  
#define     TIMER_PWM_OFFSET      20
#define     TEMP_SAME             0
#define     TEMP_HOT              1
#define     TEMP_COLD             2
#define     TEMP_THRESHOLD        5  
#define     Bitime_5              0x05*4                      
#define     Bitime                13*4
#define     UART_UPDATE_INTERVAL  1000
unsigned char BitCnt;
unsigned char applicationMode = APP_STANDBY_MODE;
unsigned char timerMode = TIMER_PWM_MODE;
unsigned char tempMode;
unsigned char calibrateUpdate = 0;
unsigned char tempPolarity = TEMP_SAME;
unsigned int TXByte;
long tempMeasured[8];
unsigned char tempMeasuredPosition=0;
long tempAverage;
long tempCalibrated, tempDifference;
void InitializeLeds(void);
void InitializeButton(void);
void PreApplicationMode(void);                     
void ConfigureAdcTempSensor(void);
void ConfigureTimerPwm(void);
void ConfigureTimerUart(void);
void Transmit(void);
void InitializeClocks(void);
void main(void)
{
  unsigned int uartUpdateTimer = UART_UPDATE_INTERVAL;
  unsigned char i;
  WDTCTL = WDTPW + WDTHOLD;                 
  InitializeClocks();
  InitializeButton();
  InitializeLeds();
  PreApplicationMode();                     
  
  applicationMode = APP_APPLICATION_MODE;
  ConfigureAdcTempSensor();
  ConfigureTimerPwm();
  __enable_interrupt();                     
  
  while(1)
  {
    ADC10CTL0 |= ENC + ADC10SC;             
    __bis_SR_register(CPUOFF + GIE);        
    
    tempMeasured[tempMeasuredPosition++] = ADC10MEM;
    if (tempMeasuredPosition == 8)
      tempMeasuredPosition = 0;
    tempAverage = 0;
    for (i = 0; i < 8; i++)
      tempAverage += tempMeasured[i];
    tempAverage >>= 3;                      
    if ((--uartUpdateTimer == 0) || calibrateUpdate )
    {
      ConfigureTimerUart();
      if (calibrateUpdate)
      {
        TXByte = 248;                       
        Transmit();
        calibrateUpdate = 0;
      }
      TXByte = (unsigned char)( ((tempAverage - 630) * 761) / 1024 );
      Transmit();
      uartUpdateTimer = UART_UPDATE_INTERVAL;
      ConfigureTimerPwm();
    }
    tempDifference = tempAverage - tempCalibrated;
    if (tempDifference < -TEMP_THRESHOLD)
    {
      tempDifference = -tempDifference;
      tempPolarity = TEMP_COLD;
      LED_OUT &= ~ LED1;
    }
    else
    if (tempDifference > TEMP_THRESHOLD)
    {
      tempPolarity = TEMP_HOT;
      LED_OUT &= ~ LED2;
    }
    else
    {
      tempPolarity = TEMP_SAME;
      TACCTL0 &= ~CCIE;
      TACCTL1 &= ~CCIE;
      LED_OUT &= ~(LED1 + LED2);
    }
    if (tempPolarity != TEMP_SAME)
    {
      tempDifference <<= 3;
      tempDifference += TIMER_PWM_OFFSET;
      TACCR1 = ( (tempDifference) < (TIMER_PWM_PERIOD-1) ? (tempDifference) : (TIMER_PWM_PERIOD-1) );
      TACCTL0 |= CCIE;
      TACCTL1 |= CCIE;
    }
  }
}
void PreApplicationMode(void)
{
  LED_DIR |= LED1 + LED2;
  LED_OUT |= LED1;                          
  LED_OUT &= ~LED2;
  BCSCTL1 |= DIVA_1;                        
  BCSCTL3 |= LFXT1S_2;                      
  TACCR0 = 1200;                             
  TACTL = TASSEL_1 | MC_1;                  
  TACCTL1 = CCIE + OUTMOD_3;                
  TACCR1 = 600;
  __bis_SR_register(LPM3_bits + GIE);          
}
void ConfigureAdcTempSensor(void)
{
  unsigned char i;
  
  ADC10CTL1 = INCH_10 + ADC10DIV_3;         
  ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE;
  __delay_cycles(1000);                     
  ADC10CTL0 |= ENC + ADC10SC;               
  __bis_SR_register(CPUOFF + GIE);          
  tempCalibrated = ADC10MEM;
  for (i=0; i < 8; i++)
    tempMeasured[i] = tempCalibrated;
  tempAverage = tempCalibrated;
}
void ConfigureTimerPwm(void)
{
  timerMode = TIMER_PWM_MODE;
  TACCR0 = TIMER_PWM_PERIOD;                              
  TACTL = TASSEL_2 | MC_1;                  
  TACCTL0 = CCIE;
  TACCTL1 = CCIE + OUTMOD_3;                
  TACCR1 = 1;
}
void ConfigureTimerUart(void)
{
  timerMode = TIMER_UART_MODE;              
  TACCTL0 = OUT;                              
  TACTL = TASSEL_2 + MC_2 + ID_3;           
  P1SEL |= TXD + RXD;                       
  P1DIR |= TXD;                             
}
void Transmit()
{
  BitCnt = 0xA;                             
  
  TACCTL0 = CM_1 + CCIS_2  + SCS + CAP + OUTMOD0;       
  TACCTL0 |= CCIS_3;                                            
  while (!(TACCTL0 & CCIFG));                           
  TACCR0 += Bitime ;                           
  TXByte |= 0x100;                          
  TXByte = TXByte << 1;                     
  TACCTL0 =  CCIS0 + OUTMOD0 + CCIE;          
  while ( TACCTL0 & CCIE );                   
}
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  if (timerMode == TIMER_UART_MODE)
  {
    TACCR0 += Bitime;                         
    if (TACCTL0 & CCIS0)                      
    {
      if ( BitCnt == 0)
      {
        P1SEL &= ~(TXD+RXD);
        TACCTL0 &= ~ CCIE ;                   
      }
      else
      {
        TACCTL0 |=  OUTMOD2;                  
        if (TXByte & 0x01)
        TACCTL0 &= ~ OUTMOD2;                 
        TXByte = TXByte >> 1;
        BitCnt --;
      }
    }
  }
  else
  {
    if (tempPolarity == TEMP_HOT)
      LED_OUT |= LED1;
    if (tempPolarity == TEMP_COLD)
      LED_OUT |= LED2;
    TACCTL0 &= ~CCIFG;
  }
}
#pragma vector=TIMERA1_VECTOR
__interrupt void ta1_isr(void)
{
  TACCTL1 &= ~CCIFG;
  if (applicationMode == APP_APPLICATION_MODE)
    LED_OUT &= ~(LED1 + LED2);
  else
    LED_OUT ^= (LED1 + LED2);
}
void InitializeClocks(void)
{
  BCSCTL1 = CALBC1_1MHZ;                    
  DCOCTL = CALDCO_1MHZ;
  BCSCTL2 &= ~(DIVS_3);                     
}
void InitializeButton(void)                 
{
  BUTTON_DIR &= ~BUTTON;
  BUTTON_OUT |= BUTTON;
  BUTTON_REN |= BUTTON;
  BUTTON_IES |= BUTTON;
  BUTTON_IFG &= ~BUTTON;
  BUTTON_IE |= BUTTON;
}
void InitializeLeds(void)
{
  LED_DIR |= LED1 + LED2;
  LED_OUT &= ~(LED1 + LED2);
}
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
  BUTTON_IFG = 0;
  BUTTON_IE &= ~BUTTON;            
  WDTCTL = WDT_ADLY_250;
  IFG1 &= ~WDTIFG;                 
  IE1 |= WDTIE;
  if (applicationMode == APP_APPLICATION_MODE)
  {
    tempCalibrated = tempAverage;
    calibrateUpdate  = 1;
  }
  else
  {
    applicationMode = APP_APPLICATION_MODE; 
    __bic_SR_register_on_exit(LPM3_bits);
  }
}
#pragma vector=WDT_VECTOR
__interrupt void WDT_ISR(void)
{
    IE1 &= ~WDTIE;                   
    IFG1 &= ~WDTIFG;                 
    WDTCTL = WDTPW + WDTHOLD;        
    BUTTON_IE |= BUTTON;             
}
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
  __bic_SR_register_on_exit(CPUOFF);        
}