/****************************************************************************************************/
/**
Copyright (c) 2008 Freescale Semiconductor
Freescale Confidential Proprietary
\file       TempMeasurement.c
\brief      
\author     Freescale Semiconductor
\author     Guadalajara Applications Laboratory RTAC Americas
\author     
\version    0.1
\date       October/2008
*/
/****************************************************************************************************/
/*                                                                                                  */
/* All software, source code, included documentation, and any implied know-how are property of      */
/* Freescale Semiconductor and therefore considered CONFIDENTIAL INFORMATION.                       */
/* This confidential information is disclosed FOR DEMONSTRATION PURPOSES ONLY.                      */
/*                                                                                                  */
/* All Confidential Information remains the property of Freescale Semiconductor and will not be     */
/* copied or reproduced without the express written permission of the Discloser, except for copies  */
/* that are absolutely necessary in order to fulfill the Purpose.                                   */
/*                                                                                                  */
/* Services performed by FREESCALE in this matter are performed AS IS and without any warranty.     */
/* CUSTOMER retains the final decision relative to the total design and functionality of the end    */
/* product.                                                                                         */
/* FREESCALE neither guarantees nor will be held liable by CUSTOMER for the success of this project.*/
/*                                                                                                  */
/* FREESCALE disclaims all warranties, express, implied or statutory including, but not limited to, */
/* implied warranty of merchantability or fitness for a particular purpose on any hardware,         */
/* software ore advise supplied to the project by FREESCALE, and or any product resulting from      */
/* FREESCALE services.                                                                              */
/* In no event shall FREESCALE be liable for incidental or consequential damages arising out of     */
/* this agreement. CUSTOMER agrees to hold FREESCALE harmless against any and all claims demands or */
/* actions by anyone on account of any damage,or injury, whether commercial, contractual, or        */
/* tortuous, rising directly or indirectly as a result of the advise or assistance supplied CUSTOMER*/ 
/* in connectionwith product, services or goods supplied under this Agreement.                      */
/*                                                                                                  */
/****************************************************************************************************/

/*****************************************************************************************************
* Include files
*****************************************************************************************************/
#include "TempMeasurement.h"

/*****************************************************************************************************
* Declaration of module wide FUNCTIONs - NOT for use in other modules
*****************************************************************************************************/
UINT8 u8TemperatureInterpolate(UINT16* TableIndex);
void vfnTempMeasurementIdle(void);
void vfnTempMeasurementGetADCConversions(void);
void vfnGetTemperature(void);
void vfnTempMeasurementGetVDD(void);

/*****************************************************************************************************
* Definition of module wide MACROs / #DEFINE-CONSTANTs - NOT for use in other modules
*****************************************************************************************************/

/*****************************************************************************************************
* Declaration of module wide TYPEs - NOT for use in other modules
*****************************************************************************************************/


/*****************************************************************************************************
* Definition of module wide VARIABLEs - NOT for use in other modules
*****************************************************************************************************/
UINT16 gu16Temperature;
UINT16 gu16ADCVDD = 300;
static UINT16 gu16ADCTempChannel;
static UINT16 gu16ADCTempAvg;
static UINT8 gu8TempADCChannel;
UINT8  gu8TempMetricSystem = _CELSIUS_;
sSM sTempMeasurementSM;

/*****************************************************************************************************
* Definition of module wide (CONST-) CONSTANTs - NOT for use in other modules
*****************************************************************************************************/
/**
* \brief Celsius table 26 valid lines + 2 lines out of valid border
*/
const UINT16 _adc_12bit_Celsius[] @0xFE60 = 
{0,                                            // out of valid table
 1188,1229,1270,1311,1354,1397,1440,1487,1526,1570,    // 10 - 19°C valid table
 1615,1659,1703,1747,1792,1837,1881,1925,1969,2014,    // 20 - 29°C valid table
 2058,2101,2144,2187,2229,2272,                        // 30 - 35°C valid table
 2273                                                  // >= 36°C out of valid table
};

/**
* \brief Fahrenheit table 46 valid lines + 2 lines out of valid border
*/
const UINT16 _adc_12bit_Fahrenheit[] @0xFE00 = 
{0,                                            // out of valid table
  1188,1211,1233,1256,1279,1302,1325,1349,1373,1397, // valid table
  1421,1444,1468,1492,1517,1541,1566,1590,1615,1639, // valid table
  1664,1688,1713,1738,1762,1787,1812,1837,1862,1886, // valid table
  1910,1935,1959,1984,2009,2033,2058,2082,2106,2129, // valid table
  2153,2177,2201,2225,2248,2272,                     // valid table
  2273                                               // out of valid table
};

/**
* \brief Index for the tables with the ADC Indexes equivalent to the temperature
*/
const UINT16* IndexTable[_TOTAL_METRIC_SYSTEMS_] =
{
  (UINT16*)(&_adc_12bit_Celsius),
  (UINT16*)(&_adc_12bit_Fahrenheit)  
};

/**
* \brief Temperature table sizes
*/
const UINT8 IndexTablesSize[_TOTAL_METRIC_SYSTEMS_] = 
{
  sizeof(_adc_12bit_Celsius)/sizeof(UINT16), 
  sizeof(_adc_12bit_Fahrenheit)/sizeof(UINT16)
};

/**
* \brief Initial temperature value
*/
const UINT8 TempOffset[_TOTAL_METRIC_SYSTEMS_] = 
{
  CELSIUS_DEGREES_START,
  FAHRENHEIT_DEGREES_START
};

/**
* \brief Table with the State Machine Functions
*/
void (*const TempMeasurementStates[]) (void) = 
{
  vfnTempMeasurementIdle,
  vfnTempMeasurementGetADCConversions,
  vfnGetTemperature,
  vfnTempMeasurementGetVDD
};
/*****************************************************************************************************
* Code of project wide FUNCTIONS
*****************************************************************************************************/
/****************************************************************************************************/
/**
* \brief    Calculate the value of the decimal point for the Temperature
* \author   Marc Loubiere
* \param    UINT16 TableIndex
* \return   UINT8 Value of the first decimal place for the temperature
* \todo     
*/
UINT8 u8TemperatureInterpolate(UINT16* TableIndex)
{
  UINT16 TempOffset1;
  UINT8  TempOffset2;
  
  TempOffset1 = 10*(gu16ADCTempAvg - (UINT16)(*TableIndex));
  TempOffset2 = (UINT16)*(TableIndex+1) - (UINT16) (*TableIndex);
  
  return ((UINT8) ((UINT16)(TempOffset1) / (UINT8)(TempOffset2)));
  
}

/**
* \brief    Initializate the TempMeasurement. A first reading is taken to have a valid Temperature on startup
* \author   Rafael Peralez
* \param    void
* \return   void
* \todo     
*/
void vfnTempMeasurement_Init(void)
{
  DISABLE_TEMP_ADC_CHANNEL();
  
  TEMP_MEASUREMENT_SET_STATE(TEMP_MEASUREMENT_IDLE);
}

/**
* \brief    Start a Temperature conversion.
* \author   Rafael Peralez
* \param    void
* \return   void
* \todo     
*/
void vfnTempMeasurementStartConversion(void)
{
  TempMeasurementInitADC();
  
  TEMP_MEASUREMENT_SET_STATE(TEMP_MEASUREMENT_GET_ADC_CONVERSIONS);
  TEMP_MEASUREMENT_NEXT_STATE(TEMP_MEASUREMENT_GET_VDD);
  /* The first measurement is not accurate*/
  TempADC_Start_conversion(BANDGAP_CHANNEL);
  gu16ADCTempAvg = ADC_Get_Conversion();
  
  gu16ADCTempAvg = 0;
  gu8TempADCChannel = BANDGAP_CHANNEL;
}

/**
* \brief    State used when there is no active Temp Measurement
* \author   Rafael Peralez
* \param    void
* \return   void
* \todo     
*/
void vfnTempMeasurementIdle(void)
{
  
}

/**
* \brief    State called when waiting for the number of ADC samples needed to make a temperature conversion
* \author   Rafael Peralez
* \param    void
* \return   void
* \todo     
*/
void vfnTempMeasurementGetADCConversions(void)
{
  static UINT8 TempADC_AverageCounter = _TEMPADC_SAMPLES_COUNT_;
  
  if (TEMP_ADC_CONVERSION_READY())
  {
    if (TempADC_AverageCounter--)
    {
      gu16ADCTempAvg += gu16ADCTempChannel;
      TempADC_Start_conversion(gu8TempADCChannel);
    }
    else
    {
      gu16ADCTempAvg /= _TEMPADC_SAMPLES_COUNT_;
      TEMP_MEASUREMENT_SET_STATE(sTempMeasurementSM.NextState);
      TempADC_AverageCounter = _TEMPADC_SAMPLES_COUNT_;
    }
  }
  
}

/**
* \brief    State called after having the ADC measurements and average. Used to convert from an ADC value to temperature
* \author   Rafael Peralez
* \param    void
* \return   void
* \todo     
*/

void vfnGetTemperature(void)
{
  UINT16* Table = (UINT16*)IndexTable[gu8TempMetricSystem];
  UINT8 Index = IndexTablesSize[gu8TempMetricSystem];
  
  THERMISTOR_PIN_PULL_UP_ENABLE;
  DISABLE_TEMP_ADC_CHANNEL();
  
  // Point to the first valid location
  Table++;
  if (gu16ADCTempAvg >= (UINT16)(*Table))
  {
    gu16Temperature = TempOffset[gu8TempMetricSystem] * 10;
    
    do
    {
      Table++;
      if ((UINT16)(*Table) >= gu16ADCTempAvg) 
      {
        break;
      }
      gu16Temperature += 10;
    }while (--Index);
    Table--;
    gu16Temperature += u8TemperatureInterpolate((UINT16*)Table);
  }
  else
  {
    gu16Temperature = TEMPERATURE_ERROR;
  }
  /* This means that the value is outside the table */
  if (!Index)
  {
    gu16Temperature = TEMPERATURE_ERROR;
  }
  
  //ADC_End();
  gu16ADCTempAvg = 0;
  TEMP_MEASUREMENT_SET_STATE(TEMP_MEASUREMENT_IDLE);
  DISABLE_TEMP_ADC_CHANNEL();
}

void vfnTempMeasurementGetVDD(void)
{  
  TEMP_MEASUREMENT_SET_STATE(TEMP_MEASUREMENT_GET_ADC_CONVERSIONS);
  TEMP_MEASUREMENT_NEXT_STATE(GET_TEMPERATURE);
  
  gu16ADCVDD = (UINT16)(((UINT32)(0xFFF) * BANDGAP_VALUE) / gu16ADCTempAvg);
  
  /* First Conversion is usually noisy and discarded */
  TempADC_Start_conversion(THERMISTOR_CHAN);
  gu16ADCTempAvg = ADC_Get_Conversion();
  gu8TempADCChannel = THERMISTOR_CHAN;
  gu16ADCTempAvg = 0;
}

/**
* \brief    Function for the State Machine. This is the interface for the caller
* \author   Rafael Peralez
* \param    void
* \return   void
* \todo     
*/
void vfnTempMeasurementSM(void)
{
  if (sTempMeasurementSM.ActualState >= (sizeof(TempMeasurementStates) / sizeof(TempMeasurementStates[0])))
  {
    TEMP_MEASUREMENT_SET_STATE(TEMP_MEASUREMENT_IDLE);
  }
  TempMeasurementStates[sTempMeasurementSM.ActualState]();
}

