/**
  ******************************************************************************
  * @file    SPIRIT_Radio.c
  * @author  VMA division - AMS
  * @version 3.2.2
  * @date    08-July-2015
  * @brief   This file provides all the low level API to manage Analog and Digital
  *          radio part of SPIRIT.
  * @details
  *
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "SPIRIT_Radio.h"
#include "MCU_Interface.h"
#include <math.h>

//180619 HJM : init 재시작을 위한 카운팅 변수
static int iSpiritRadioErrorCounting = 0;
#define MAX_ERROR_COUNTING  3
#define RETURN_ERROR_NUMBER     100

/** @addtogroup SPIRIT_Libraries
* @{
*/


/** @addtogroup SPIRIT_Radio
* @{
*/


/** @defgroup Radio_Private_TypesDefinitions            Radio Private Types Definitions
* @{
*/


/**
* @}
*/


/** @defgroup Radio_Private_Defines                     Radio Private Defines
* @{
*/




/**
* @}
*/


/** @defgroup Radio_Private_Macros                      Radio Private Macros
* @{
*/
#define XTAL_FLAG(xtalFrequency)               (xtalFrequency>=25e6) ? XTAL_FLAG_26_MHz:XTAL_FLAG_24_MHz

#define ROUND(A)                                  (((A-(uint32_t)A)> 0.5)? (uint32_t)A+1:(uint32_t)A)
/**
* @}
*/


/** @defgroup Radio_Private_Variables                   Radio Private Variables
* @{
*/
/**
* @brief  The Xtal frequency. To be set by the user (see SetXtalFreq() function)
*/
static uint32_t s_lXtalFrequency;

/**
* @brief  Factor is: B/2 used in the formula for SYNTH word calculation
*/
static const uint8_t s_vectcBHalfFactor[4]={(HIGH_BAND_FACTOR/2), (MIDDLE_BAND_FACTOR/2), (LOW_BAND_FACTOR/2), (VERY_LOW_BAND_FACTOR/2)};

/**
* @brief  BS value to write in the SYNT0 register according to the selected band
*/
static const uint8_t s_vectcBandRegValue[4]={SYNT0_BS_6, SYNT0_BS_12, SYNT0_BS_16, SYNT0_BS_32};


/**
* @brief  It represents the available channel bandwidth times 10 for 26 Mhz xtal.
* @note   The channel bandwidth for others xtal frequencies can be computed since this table
*         multiplying the current table by a factor xtal_frequency/26e6.
*/
static const uint16_t s_vectnBandwidth26M[90]=
{
  8001, 7951, 7684, 7368, 7051, 6709, 6423, 5867, 5414, \
    4509, 4259, 4032, 3808, 3621, 3417, 3254, 2945, 2703, \
      2247, 2124, 2015, 1900, 1807, 1706, 1624, 1471, 1350, \
        1123, 1062, 1005,  950,  903,  853,  812,  735,  675, \
          561,  530,  502,  474,  451,  426,  406,  367,  337, \
            280,  265,  251,  237,  226,  213,  203,  184,  169, \
              140,  133,  126,  119,  113,  106,  101,   92,   84, \
                70,   66,   63,   59,   56,   53,   51,   46,   42, \
                  35,   33,   31,   30,   28,   27,   25,   23,   21, \
                    18,   17,   16,   15,   14,   13,   13,   12,   11
};

/**
* @brief  It represents the available VCO frequencies
*/
static const uint16_t s_vectnVCOFreq[16]=
{
  4644, 4708, 4772, 4836, 4902, 4966, 5030, 5095, \
    5161, 5232, 5303, 5375, 5448, 5519, 5592, 5663
};

/**
* @brief  This variable is used to enable or disable
*  the VCO calibration WA called at the end of the SpiritRadioSetFrequencyBase fcn.
*  Default is enabled.
*/
static SpiritFunctionalState xDoVcoCalibrationWA=S_ENABLE;


/**
* @brief  These values are used to interpolate the power curves.
*         Interpolation curves are linear in the following 3 regions:
*       - reg value: 1 to 13    (up region)
*       - reg value: 13 to 40   (mid region)
*       - reg value: 41 to 90   (low region)
*       power_reg = m*power_dBm + q
*       For each band the order is: {m-up, q-up, m-mid, q-mid, m-low, q-low}.
* @note The power interpolation curves have been extracted
*       by measurements done on the divisional evaluation boards.
*/
static const float fPowerFactors[5][6]={ 
  {-2.11,25.66,-2.11,25.66,-2.00,31.28},   /* 915 */
  {-2.04,23.45,-2.04,23.45,-1.95,27.66},   /* 868 */
  {-3.48,38.45,-1.89,27.66,-1.92,30.23},   /* 433 */
  {-3.27,35.43,-1.80,26.31,-1.89,29.61},   /* 315 */
  {-4.18,50.66,-1.80,30.04,-1.86,32.22},   /* 169 */
};

/**
* @}
*/


/** @defgroup Radio_Private_FunctionPrototypes          Radio Private Function Prototypes
* @{
*/


/**
* @}
*/


/** @defgroup Radio_Private_Functions                    Radio Private Functions
* @{
*/

/**
* @brief  Initializes the SPIRIT analog and digital radio part according to the specified
*         parameters in the pxSRadioInitStruct.
* @param  pxSRadioInitStruct pointer to a SRadioInit structure that
*         contains the configuration information for the analog radio part of SPIRIT.
* @retval Error code: 0=no error, 1=error during calibration of VCO.
*/
uint8_t SpiritRadioInit(SRadioInit* pxSRadioInitStruct)
{
  printf("[INIT_REVISE]SpiritRadioInit start...\n");
  int32_t FOffsetTmp;
  uint8_t anaRadioRegArray[8], digRadioRegArray[4];
  int16_t xtalOffsetFactor;
  uint8_t drM, drE, FdevM, FdevE, bwM, bwE;
    
  /* Workaround for Vtune */
  printf("test 9-1\n");
  uint8_t value = 0xA0; 
  SpiritSpiWriteRegisters(0x9F, 1, &value);
  
  /* Calculates the offset respect to RF frequency and according to xtal_ppm parameter: (xtal_ppm*FBase)/10^6 */
  printf("test 9-2\n");
  FOffsetTmp = (int32_t)(((float)pxSRadioInitStruct->nXtalOffsetPpm*pxSRadioInitStruct->lFrequencyBase)/PPM_FACTOR);
  
  /* Check the parameters */
  printf("test 9-3\n");
  s_assert_param(IS_FREQUENCY_BAND(pxSRadioInitStruct->lFrequencyBase));
  s_assert_param(IS_MODULATION_SELECTED(pxSRadioInitStruct->xModulationSelect));
  s_assert_param(IS_DATARATE(pxSRadioInitStruct->lDatarate));
  s_assert_param(IS_FREQUENCY_OFFSET(FOffsetTmp,s_lXtalFrequency));
  s_assert_param(IS_CHANNEL_SPACE(pxSRadioInitStruct->nChannelSpace,s_lXtalFrequency));
  s_assert_param(IS_F_DEV(pxSRadioInitStruct->lFreqDev,s_lXtalFrequency));
  
  /* Disable the digital, ADC, SMPS reference clock divider if fXO>24MHz or fXO<26MHz */
  printf("test 9-4\n");
  SpiritSpiCommandStrobes(COMMAND_STANDBY);    
  do{
    /* Delay for state transition */
    for(volatile uint8_t i=0; i!=0xFF; i++);
    
    /* Reads the MC_STATUS register */
    SpiritRefreshStatus();
    printf("test 9-4 g_xStatus.MC_STATE : [0x%02X]\n", g_xStatus.MC_STATE);
    ++iSpiritRadioErrorCounting;
    if (iSpiritRadioErrorCounting >= MAX_ERROR_COUNTING)
    {
        iSpiritRadioErrorCounting = 0;
//        reset_board();
        return RETURN_ERROR_NUMBER;
    }
  }while(g_xStatus.MC_STATE!=MC_STATE_STANDBY);
  iSpiritRadioErrorCounting = 0;
  
  
  
  
  
  if(s_lXtalFrequency<DOUBLE_XTAL_THR)
  {
    SpiritRadioSetDigDiv(S_DISABLE);
    s_assert_param(IS_CH_BW(pxSRadioInitStruct->lBandwidth,s_lXtalFrequency));
  }
  else
  {      
    SpiritRadioSetDigDiv(S_ENABLE);
    s_assert_param(IS_CH_BW(pxSRadioInitStruct->lBandwidth,(s_lXtalFrequency>>1)));
  }
  
  
  
  
  
  
  
  
  /* Goes in READY state */
  printf("test 9-5\n");
  SpiritSpiCommandStrobes(COMMAND_READY);
  do{
    /* Delay for state transition */
    for(volatile uint8_t i=0; i!=0xFF; i++);
    
    /* Reads the MC_STATUS register */
    SpiritRefreshStatus();
    printf("test 9-5 g_xStatus.MC_STATE : [%d]\n", g_xStatus.MC_STATE);
    ++iSpiritRadioErrorCounting;
    if (iSpiritRadioErrorCounting >= MAX_ERROR_COUNTING)
    {
        iSpiritRadioErrorCounting = 0;
//        reset_board();
        return RETURN_ERROR_NUMBER;
    }
  }while(g_xStatus.MC_STATE!=MC_STATE_READY);
  iSpiritRadioErrorCounting = 0;
  
  /* Calculates the FC_OFFSET parameter and cast as signed int: FOffsetTmp = (Fxtal/2^18)*FC_OFFSET */
  printf("test 9-6\n");
  xtalOffsetFactor = (int16_t)(((float)FOffsetTmp*FBASE_DIVIDER)/s_lXtalFrequency);
  anaRadioRegArray[2] = (uint8_t)((((uint16_t)xtalOffsetFactor)>>8)&0x0F);
  anaRadioRegArray[3] = (uint8_t)(xtalOffsetFactor);
  
  /* Calculates the channel space factor */
  printf("test 9-7\n");
  anaRadioRegArray[0] =((uint32_t)pxSRadioInitStruct->nChannelSpace<<9)/(s_lXtalFrequency>>6)+1;
  
  SpiritManagementWaTRxFcMem(pxSRadioInitStruct->lFrequencyBase);
  
  
  
  
  
  
  /* 2nd order DEM algorithm enabling */
  printf("test 9-8\n");
  uint8_t tmpreg; SpiritSpiReadRegisters(0xA3, 1, &tmpreg);
  tmpreg &= ~0x02; SpiritSpiWriteRegisters(0xA3, 1, &tmpreg);
  
  /* Check the channel center frequency is in one of the possible range */
  printf("test 9-9\n");
  s_assert_param(IS_FREQUENCY_BAND((pxSRadioInitStruct->lFrequencyBase + ((xtalOffsetFactor*s_lXtalFrequency)/FBASE_DIVIDER) + pxSRadioInitStruct->nChannelSpace * pxSRadioInitStruct->cChannelNumber)));  
  
  /* Calculates the datarate mantissa and exponent */
  printf("test 9-10\n");
  SpiritRadioSearchDatarateME(pxSRadioInitStruct->lDatarate, &drM, &drE);
  digRadioRegArray[0] = (uint8_t)(drM);
  digRadioRegArray[1] = (uint8_t)(0x00 | pxSRadioInitStruct->xModulationSelect |drE);
  
  /* Read the fdev register to preserve the clock recovery algo bit */
  printf("test 9-11\n");
  SpiritSpiReadRegisters(0x1C, 1, &tmpreg);
  
  /* Calculates the frequency deviation mantissa and exponent */
  printf("test 9-12\n");
  SpiritRadioSearchFreqDevME(pxSRadioInitStruct->lFreqDev, &FdevM, &FdevE);
  digRadioRegArray[2] = (uint8_t)((FdevE<<4) | (tmpreg&0x08) | FdevM);
  
  
  /* Calculates the channel filter mantissa and exponent */
  printf("test 9-13\n");
  SpiritRadioSearchChannelBwME(pxSRadioInitStruct->lBandwidth, &bwM, &bwE);
  
  
  
  digRadioRegArray[3] = (uint8_t)((bwM<<4) | bwE);
 
 
  float if_off=(3.0*480140)/(s_lXtalFrequency>>12)-64;
  
  
  uint8_t ifOffsetAna = ROUND(if_off);
  
  
  if(s_lXtalFrequency<DOUBLE_XTAL_THR)
  {
    /* if offset digital is the same in case of single xtal */
    anaRadioRegArray[1] = ifOffsetAna;
  }
  else
  {
    if_off=(3.0*480140)/(s_lXtalFrequency>>13)-64;
    
    /* ... otherwise recompute it */
    anaRadioRegArray[1] = ROUND(if_off);
  }
//  if(s_lXtalFrequency==24000000) {
//    ifOffsetAna = 0xB6;
//    anaRadioRegArray[1] = 0xB6;
//  }
//  if(s_lXtalFrequency==25000000) {
//    ifOffsetAna = 0xAC;
//    anaRadioRegArray[1] = 0xAC;
//  }
//  if(s_lXtalFrequency==26000000) {
//    ifOffsetAna = 0xA3;
//    anaRadioRegArray[1] = 0xA3;
//  }
//  if(s_lXtalFrequency==48000000) {
//    ifOffsetAna = 0x3B;
//    anaRadioRegArray[1] = 0xB6;
//  }
//  if(s_lXtalFrequency==50000000) {
//    ifOffsetAna = 0x36;
//    anaRadioRegArray[1] = 0xAC;
//  }
//  if(s_lXtalFrequency==52000000) {
//    ifOffsetAna = 0x31;
//    anaRadioRegArray[1] = 0xA3;
//  }
  
  g_xStatus = SpiritSpiWriteRegisters(IF_OFFSET_ANA_BASE, 1, &ifOffsetAna);

  
  /* Sets Xtal configuration */
  printf("test 9-14\n");
  if(s_lXtalFrequency>DOUBLE_XTAL_THR)
  {
    SpiritRadioSetXtalFlag(XTAL_FLAG((s_lXtalFrequency/2)));
  }
  else
  {
    SpiritRadioSetXtalFlag(XTAL_FLAG(s_lXtalFrequency));
  }
  
  /* Sets the channel number in the corresponding register */
  printf("test 9-15\n");
  SpiritSpiWriteRegisters(CHNUM_BASE, 1, &pxSRadioInitStruct->cChannelNumber);
  
  /* Configures the Analog Radio registers */
  printf("test 9-16\n");
  SpiritSpiWriteRegisters(CHSPACE_BASE, 4, anaRadioRegArray);
  
  /* Configures the Digital Radio registers */
  printf("test 9-17\n");
  g_xStatus = SpiritSpiWriteRegisters(MOD1_BASE, 4, digRadioRegArray);
  
  /* Enable the freeze option of the AFC on the SYNC word */
  printf("test 9-18\n");
  SpiritRadioAFCFreezeOnSync(S_ENABLE);
  
  /* Set the IQC correction optimal value */
  printf("test 9-19\n");
  anaRadioRegArray[0]=0x80;
  anaRadioRegArray[1]=0xE3;
  g_xStatus = SpiritSpiWriteRegisters(0x99, 2, anaRadioRegArray);
  
  printf("[INIT_REVISE]SpiritRadioInit end.\n");
  
  return SpiritRadioSetFrequencyBase(pxSRadioInitStruct->lFrequencyBase);
}


/**
* @brief  Returns the SPIRIT analog and digital radio structure according to the registers value.
* @param  pxSRadioInitStruct pointer to a SRadioInit structure that
*         contains the configuration information for the analog radio part of SPIRIT.
* @retval None.
*/
void SpiritRadioGetInfo(SRadioInit* pxSRadioInitStruct)
{
  uint8_t anaRadioRegArray[8], digRadioRegArray[4];
  BandSelect band;
  int16_t xtalOffsetFactor;
  
  /* Get the RF board version */
  //SpiritVersion xSpiritVersion = SpiritGeneralGetSpiritVersion();
  
  /* Reads the Analog Radio registers */
  SpiritSpiReadRegisters(SYNT3_BASE, 8, anaRadioRegArray);
  
  /* Reads the Digital Radio registers */
  g_xStatus = SpiritSpiReadRegisters(MOD1_BASE, 4, digRadioRegArray);
  
  /* Reads the operating band masking the Band selected field */
  if((anaRadioRegArray[3] & 0x07) == SYNT0_BS_6)
  {
    band = HIGH_BAND;
  }
  else if ((anaRadioRegArray[3] & 0x07) == SYNT0_BS_12)
  {
    band = MIDDLE_BAND;
  }
  else if ((anaRadioRegArray[3] & 0x07) == SYNT0_BS_16)
  {
    band = LOW_BAND;
  }
  else if ((anaRadioRegArray[3] & 0x07) == SYNT0_BS_32)
  {
    band = VERY_LOW_BAND;
  }
  else
  {
    /* if it is another value, set it to a valid one in order to avoid access violation */
    uint8_t tmp=(anaRadioRegArray[3]&0xF8)|SYNT0_BS_6;
    SpiritSpiWriteRegisters(SYNT0_BASE,1,&tmp);
    band = HIGH_BAND;
  }
  
  /* Computes the synth word */
  uint32_t synthWord = (uint32_t)((((uint32_t)(anaRadioRegArray[0]&0x1F))<<21)+(((uint32_t)(anaRadioRegArray[1]))<<13)+\
    (((uint32_t)(anaRadioRegArray[2]))<<5)+(((uint32_t)(anaRadioRegArray[3]))>>3));
  
  /* Calculates the frequency base */
  uint8_t cRefDiv = (uint8_t)SpiritRadioGetRefDiv()+1;
  pxSRadioInitStruct->lFrequencyBase = (uint32_t)round(synthWord*(((double)s_lXtalFrequency)/(FBASE_DIVIDER*cRefDiv*s_vectcBHalfFactor[band])));
  
  /* Calculates the Offset Factor */
  uint16_t xtalOffTemp = ((((uint16_t)anaRadioRegArray[6])<<8)+((uint16_t)anaRadioRegArray[7]));
  
  /* If a negative number then convert the 12 bit 2-complement in a 16 bit number */
  if(xtalOffTemp & 0x0800)
  {
    xtalOffTemp = xtalOffTemp | 0xF000;
  }
  else
  {
    xtalOffTemp = xtalOffTemp & 0x0FFF;
  }
  
  xtalOffsetFactor = *((int16_t*)(&xtalOffTemp));
  
  /* Calculates the frequency offset in ppm */
  pxSRadioInitStruct->nXtalOffsetPpm =(int16_t)((uint32_t)xtalOffsetFactor*s_lXtalFrequency*PPM_FACTOR)/((uint32_t)FBASE_DIVIDER*pxSRadioInitStruct->lFrequencyBase);
  
  /* Channel space */
  pxSRadioInitStruct->nChannelSpace = anaRadioRegArray[4]*(s_lXtalFrequency>>15);
  
  /* Channel number */
  pxSRadioInitStruct->cChannelNumber = SpiritRadioGetChannel();
  
  /* Modulation select */
  pxSRadioInitStruct->xModulationSelect = (ModulationSelect)(digRadioRegArray[1] & 0x70);
  
  /* Reads the frequency deviation for mantissa and exponent */
  uint8_t FDevM = digRadioRegArray[2]&0x07;
  uint8_t FDevE = (digRadioRegArray[2]&0xF0)>>4;
  
  /* Reads the channel filter register for mantissa and exponent */
  uint8_t bwM = (digRadioRegArray[3]&0xF0)>>4;
  uint8_t bwE = digRadioRegArray[3]&0x0F;
  
  uint8_t cDivider = 0;
  cDivider = SpiritRadioGetDigDiv();
  
  /* Calculates the datarate */
  pxSRadioInitStruct->lDatarate = ((s_lXtalFrequency>>(5+cDivider))*(256+digRadioRegArray[0]))>>(23-(digRadioRegArray[1]&0x0F));
  
  /* Calculates the frequency deviation */
  // (((s_lXtalFrequency>>6)*(8+FDevM))>>(12-FDevE+cCorrection));
  pxSRadioInitStruct->lFreqDev =(uint32_t)((float)s_lXtalFrequency/(((uint32_t)1)<<18)*(uint32_t)((8.0+FDevM)/2*(1<<FDevE)));
  
  /* Reads the channel filter bandwidth from the look-up table and return it */
  pxSRadioInitStruct->lBandwidth = (uint32_t)(100.0*s_vectnBandwidth26M[bwM+(bwE*9)]*((s_lXtalFrequency>>cDivider)/26e6));
  
}


/**
* @brief  Sets the Xtal configuration in the ANA_FUNC_CONF0 register.
* @param  xXtal one of the possible value of the enum type XtalFrequency.
*         @arg XTAL_FLAG_24_MHz:  in case of 24 MHz crystal
*         @arg XTAL_FLAG_26_MHz:  in case of 26 MHz crystal
* @retval None.
*/
void SpiritRadioSetXtalFlag(XtalFlag xXtal)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_XTAL_FLAG(xXtal));
  
  /* Reads the ANA_FUNC_CONF_0 register */
  g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue);
  if(xXtal == XTAL_FLAG_26_MHz)
  {
    tempRegValue|=SELECT_24_26_MHZ_MASK;
  }
  else
  {
    tempRegValue &= (~SELECT_24_26_MHZ_MASK);
  }
  
  /* Sets the 24_26MHz_SELECT field in the ANA_FUNC_CONF_0 register */
  g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the Xtal configuration in the ANA_FUNC_CONF0 register.
* @param  None.
* @retval XtalFrequency Settled Xtal configuration.
*/
XtalFlag SpiritRadioGetXtalFlag(void)
{
  uint8_t tempRegValue;
  
  /* Reads the Xtal configuration in the ANA_FUNC_CONF_0 register and return the value */
  g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue);
  
  return (XtalFlag)((tempRegValue & 0x40)>>6);
  
}


/**
* @brief  Returns the charge pump word for a given VCO frequency.
* @param  lFc channel center frequency expressed in Hz.
*         This parameter can be a value in one of the following ranges:<ul>
*         <li> High_Band: from 779 MHz to 915 MHz </li>
*         <li> Middle Band: from 387 MHz to 470 MHz </li>
*         <li> Low Band: from 300 MHz to 348 MHz </li>
*         <li> Very low Band: from 150 MHz to 174 MHz </li> </ul>
* @retval uint8_t Charge pump word.
*/
uint8_t SpiritRadioSearchWCP(uint32_t lFc)
{
  int8_t i;
  uint32_t vcofreq;
  uint8_t BFactor;
  
  /* Check the channel center frequency is in one of the possible range */
  s_assert_param(IS_FREQUENCY_BAND(lFc));
  
  /* Search the operating band */
  if(IS_FREQUENCY_BAND_HIGH(lFc))
  {
    BFactor = HIGH_BAND_FACTOR;
  }
  else if(IS_FREQUENCY_BAND_MIDDLE(lFc))
  {
    BFactor = MIDDLE_BAND_FACTOR;
  }
  else if(IS_FREQUENCY_BAND_LOW(lFc))
  {
    BFactor = LOW_BAND_FACTOR;
  }
  else
  {
    BFactor = VERY_LOW_BAND_FACTOR;
  }
  
  /* Calculates the VCO frequency VCOFreq = lFc*B */
  vcofreq = (lFc/1000000)*BFactor;
  
  /* Search in the vco frequency array the charge pump word */
  if(vcofreq>=s_vectnVCOFreq[15])
  {
    i=15;
  }
  else
  {
    /* Search the value */
    for(i=0 ; i<15 && vcofreq>s_vectnVCOFreq[i] ; i++);
    
    /* Be sure that it is the best approssimation */
    if (i!=0 && s_vectnVCOFreq[i]-vcofreq>vcofreq-s_vectnVCOFreq[i-1])
      i--;
  }
  
  /* Return index */
  return (i%8);
  
}

/**
* @brief  Returns the synth word.
* @param  None.
* @retval uint32_t Synth word.
*/
uint32_t SpiritRadioGetSynthWord(void)
{
  uint8_t regArray[4];
  
  /* Reads the SYNTH registers, build the synth word and return it */
  g_xStatus = SpiritSpiReadRegisters(SYNT3_BASE, 4, regArray);
  return ((((uint32_t)(regArray[0]&0x1F))<<21)+(((uint32_t)(regArray[1]))<<13)+\
    (((uint32_t)(regArray[2]))<<5)+(((uint32_t)(regArray[3]))>>3));
  
}


/**
* @brief  Sets the SYNTH registers.
* @param  lSynthWord the synth word to write in the SYNTH[3:0] registers.
* @retval None.
*/
void SpiritRadioSetSynthWord(uint32_t lSynthWord)
{
  uint8_t tempArray[4];
  uint8_t tempRegValue;
  
  /* Reads the SYNT0 register */
  g_xStatus = SpiritSpiReadRegisters(SYNT0_BASE, 1, &tempRegValue);
  
  /* Mask the Band selected field */
  tempRegValue &= 0x07;
  
  /* Build the array for SYNTH registers */
  tempArray[0] = (uint8_t)((lSynthWord>>21)&(0x0000001F));
  tempArray[1] = (uint8_t)((lSynthWord>>13)&(0x000000FF));
  tempArray[2] = (uint8_t)((lSynthWord>>5)&(0x000000FF));
  tempArray[3] = (uint8_t)(((lSynthWord&0x0000001F)<<3)| tempRegValue);
  
  /* Writes the synth word in the SYNTH registers */
  g_xStatus = SpiritSpiWriteRegisters(SYNT3_BASE, 4, tempArray);
  
}


/**
* @brief  Sets the operating band.
* @param  xBand the band to set.
*         This parameter can be one of following parameters:
*         @arg  HIGH_BAND   High_Band selected: from 779 MHz to 915 MHz
*         @arg  MIDDLE_BAND: Middle Band selected: from 387 MHz to 470 MHz
*         @arg  LOW_BAND:  Low Band selected: from 300 MHz to 348 MHz
*         @arg  VERY_LOW_BAND:  Very low Band selected: from 150 MHz to 174 MHz
* @retval None.
*/
void SpiritRadioSetBand(BandSelect xBand)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_BAND_SELECTED(xBand));
  
  /* Reads the SYNT0 register*/
  g_xStatus = SpiritSpiReadRegisters(SYNT0_BASE, 1, &tempRegValue);
  
  /* Mask the SYNTH[4;0] field and write the BS value */
  tempRegValue &= 0xF8;
  tempRegValue |= s_vectcBandRegValue[xBand];
  
  /* Configures the SYNT0 register setting the operating band */
  g_xStatus = SpiritSpiWriteRegisters(SYNT0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the operating band.
* @param  None.
* @retval BandSelect Settled band.
*         This returned value can be one of the following parameters:
*         @arg  HIGH_BAND   High_Band selected: from 779 MHz to 915 MHz
*         @arg  MIDDLE_BAND: Middle Band selected: from 387 MHz to 470 MHz
*         @arg  LOW_BAND:  Low Band selected: from 300 MHz to 348 MHz
*         @arg  VERY_LOW_BAND:  Very low Band selected: from 150 MHz to 174 MHz
*/
BandSelect SpiritRadioGetBand(void)
{
  uint8_t tempRegValue;
  
  /* Reads the SYNT0 register */
  g_xStatus = SpiritSpiReadRegisters(SYNT0_BASE, 1, &tempRegValue);
  
  /* Mask the Band selected field */
  if((tempRegValue & 0x07) == SYNT0_BS_6)
  {
    return HIGH_BAND;
  }
  else if ((tempRegValue & 0x07) == SYNT0_BS_12)
  {
    return MIDDLE_BAND;
  }
  else if ((tempRegValue & 0x07) == SYNT0_BS_16)
  {
    return LOW_BAND;
  }
  else
  {
    return VERY_LOW_BAND;
  }
  
}


/**
* @brief  Sets the channel number.
* @param  cChannel the channel number.
* @retval None.
*/
void SpiritRadioSetChannel(uint8_t cChannel)
{
  /* Writes the CHNUM register */
  g_xStatus = SpiritSpiWriteRegisters(CHNUM_BASE, 1, &cChannel);
  
}


/**
* @brief  Returns the actual channel number.
* @param  None.
* @retval uint8_t Actual channel number.
*/
uint8_t SpiritRadioGetChannel(void)
{
  uint8_t tempRegValue;
  
  /* Reads the CHNUM register and return the value */
  g_xStatus = SpiritSpiReadRegisters(CHNUM_BASE, 1, &tempRegValue);
  
  return tempRegValue;
  
}


/**
* @brief  Sets the channel space factor in channel space register.
*         The channel spacing step is computed as F_Xo/32768.
* @param  fChannelSpace the channel space expressed in Hz.
* @retval None.
*/
void SpiritRadioSetChannelSpace(uint32_t fChannelSpace)
{
  uint8_t cChannelSpaceFactor;
  
  /* Round to the nearest integer */
  cChannelSpaceFactor = ((uint32_t)fChannelSpace*CHSPACE_DIVIDER)/s_lXtalFrequency;
  
  /* Write value into the register */
  g_xStatus = SpiritSpiWriteRegisters(CHSPACE_BASE, 1, &cChannelSpaceFactor);
  
}


/**
* @brief  Returns the channel space register.
* @param  None.
* @retval uint32_t Channel space. The channel space is: CS = channel_space_factor x XtalFrequency/2^15
*         where channel_space_factor is the CHSPACE register value.
*/
uint32_t SpiritRadioGetChannelSpace(void)
{
  uint8_t channelSpaceFactor;
  
  /* Reads the CHSPACE register, calculate the channel space and return it */
  g_xStatus = SpiritSpiReadRegisters(CHSPACE_BASE, 1, &channelSpaceFactor);
  
  /* Compute the Hertz value and return it */
  return ((channelSpaceFactor*s_lXtalFrequency)/CHSPACE_DIVIDER);
  
}


/**
* @brief  Sets the FC OFFSET register starting from xtal ppm value.
* @param  nXtalPpm the xtal offset expressed in ppm.
* @retval None.
*/
void SpiritRadioSetFrequencyOffsetPpm(int16_t nXtalPpm)
{
  uint8_t tempArray[2];
  int16_t xtalOffsetFactor;
  uint32_t synthWord, fBase;
  int32_t FOffsetTmp;
  BandSelect band;
  
  /* Reads the synth word */
  synthWord = SpiritRadioGetSynthWord();
  
  /* Reads the operating band */
  band = SpiritRadioGetBand();
  
  /* Calculates the frequency base */
  uint8_t cRefDiv = (uint8_t)SpiritRadioGetRefDiv()+1;
  fBase = synthWord*(s_lXtalFrequency/(s_vectcBHalfFactor[band]*cRefDiv)/FBASE_DIVIDER);
  
  /* Calculates the offset respect to RF frequency and according to xtal_ppm parameter */
  FOffsetTmp = (int32_t)(((float)nXtalPpm*fBase)/PPM_FACTOR);
  
  /* Check the Offset is in the correct range */
  s_assert_param(IS_FREQUENCY_OFFSET(FOffsetTmp,s_lXtalFrequency));
  
  /* Calculates the FC_OFFSET value to write in the corresponding register */  
  xtalOffsetFactor = (int16_t)(((float)FOffsetTmp*FBASE_DIVIDER)/s_lXtalFrequency);
  
  /* Build the array related to the FC_OFFSET_1 and FC_OFFSET_0 register */
  tempArray[0]=(uint8_t)((((uint16_t)xtalOffsetFactor)>>8)&0x0F);
  tempArray[1]=(uint8_t)(xtalOffsetFactor);
  
  /* Writes the FC_OFFSET registers */
  g_xStatus = SpiritSpiWriteRegisters(FC_OFFSET1_BASE, 2, tempArray);
  
}


/**
* @brief  Sets the FC OFFSET register starting from frequency offset expressed in Hz.
* @param  lFOffset frequency offset expressed in Hz as signed word.
* @retval None.
*/
void SpiritRadioSetFrequencyOffset(int32_t lFOffset)
{
  uint8_t tempArray[2];
  int16_t offset;
  
  /* Check that the Offset is in the correct range */
  s_assert_param(IS_FREQUENCY_OFFSET(lFOffset,s_lXtalFrequency));
  
  /* Calculates the offset value to write in the FC_OFFSET register */
  offset = (int16_t)(((float)lFOffset*FBASE_DIVIDER)/s_lXtalFrequency);
  
  /* Build the array related to the FC_OFFSET_1 and FC_OFFSET_0 register */
  tempArray[0]=(uint8_t)((((uint16_t)offset)>>8)&0x0F);
  tempArray[1]=(uint8_t)(offset);
  
  /* Writes the FC_OFFSET registers */
  g_xStatus = SpiritSpiWriteRegisters(FC_OFFSET1_BASE, 2, tempArray);
  
}


/**
* @brief  Returns the actual frequency offset.
* @param  None.
* @retval int32_t Frequency offset expressed in Hz as signed word.
*/
int32_t SpiritRadioGetFrequencyOffset(void)
{
  uint8_t tempArray[2];
  int16_t xtalOffsetFactor;
  
  /* Reads the FC_OFFSET registers */
  g_xStatus = SpiritSpiReadRegisters(FC_OFFSET1_BASE, 2, tempArray);
  
  /* Calculates the Offset Factor */
  uint16_t xtalOffTemp = ((((uint16_t)tempArray[0])<<8)+((uint16_t)tempArray[1]));
  
  if(xtalOffTemp & 0x0800)
  {
    xtalOffTemp = xtalOffTemp | 0xF000;
  }
  else
  {
    xtalOffTemp = xtalOffTemp & 0x0FFF;
  }
  
  xtalOffsetFactor = *((int16_t*)(&xtalOffTemp));
  
  /* Calculates the frequency offset and return it */
  return ((int32_t)(xtalOffsetFactor*s_lXtalFrequency)/FBASE_DIVIDER);
  
}



/**
* @brief  Sets the Synth word and the Band Select register according to desired base carrier frequency.
*         In this API the Xtal configuration is read out from
*         the corresponding register. The user shall fix it before call this API.
* @param  lFBase the base carrier frequency expressed in Hz as unsigned word.
* @retval Error code: 0=no error, 1=error during calibration of VCO.
*/
uint8_t SpiritRadioSetFrequencyBase(uint32_t lFBase)
{
  uint32_t synthWord, Fc;
  uint8_t band, anaRadioRegArray[4], wcp;
  
  /* Check the parameter */
  s_assert_param(IS_FREQUENCY_BAND(lFBase));
  
  /* Search the operating band */
  if(IS_FREQUENCY_BAND_HIGH(lFBase))
  {
    band = HIGH_BAND;
  }
  else if(IS_FREQUENCY_BAND_MIDDLE(lFBase))
  {
    band = MIDDLE_BAND;
  }
  else if(IS_FREQUENCY_BAND_LOW(lFBase))
  {
    band = LOW_BAND;
  }
  else
  {
    band = VERY_LOW_BAND;
  }
  
  int32_t FOffset  = SpiritRadioGetFrequencyOffset();
  uint32_t lChannelSpace  = SpiritRadioGetChannelSpace();
  uint8_t cChannelNum = SpiritRadioGetChannel();
  
  /* Calculates the channel center frequency */
  Fc = lFBase + FOffset + lChannelSpace*cChannelNum;
  
  /* Reads the reference divider */
  uint8_t cRefDiv = (uint8_t)SpiritRadioGetRefDiv()+1;
  
  /* Selects the VCO */
  switch(band)
  {
  case VERY_LOW_BAND:
    if(Fc<161281250)
    {
      SpiritCalibrationSelectVco(VCO_L);
    }
    else
    {
      SpiritCalibrationSelectVco(VCO_H);
    }
    break;
    
  case LOW_BAND:
    if(Fc<322562500)
    {
      SpiritCalibrationSelectVco(VCO_L);
    }
    else
    {
      SpiritCalibrationSelectVco(VCO_H);
    }
    break;
    
  case MIDDLE_BAND:
    if(Fc<430083334)
    {
      SpiritCalibrationSelectVco(VCO_L);
    }
    else
    {
      SpiritCalibrationSelectVco(VCO_H);
    }
    break;
    
  case HIGH_BAND:
    if(Fc<860166667)
    {
      SpiritCalibrationSelectVco(VCO_L);
    }
    else
    {
      SpiritCalibrationSelectVco(VCO_H);
    }
  }
  
  /* Search the VCO charge pump word and set the corresponding register */
  wcp = SpiritRadioSearchWCP(Fc);
  
  synthWord = (uint32_t)(lFBase*s_vectcBHalfFactor[band]*(((double)(FBASE_DIVIDER*cRefDiv))/s_lXtalFrequency));
  
  /* Build the array of registers values for the analog part */
  anaRadioRegArray[0] = (uint8_t)(((synthWord>>21)&(0x0000001F))|(wcp<<5));
  anaRadioRegArray[1] = (uint8_t)((synthWord>>13)&(0x000000FF));
  anaRadioRegArray[2] = (uint8_t)((synthWord>>5)&(0x000000FF));
  anaRadioRegArray[3] = (uint8_t)(((synthWord&0x0000001F)<<3)| s_vectcBandRegValue[band]);
  
  /* Configures the needed Analog Radio registers */
  g_xStatus = SpiritSpiWriteRegisters(SYNT3_BASE, 4, anaRadioRegArray);
  
  if(xDoVcoCalibrationWA==S_ENABLE)
    return SpiritManagementWaVcoCalibration();
  
  return 0;
}

/**
* @brief  To say to the set frequency base if do or not the VCO calibration WA.
* @param  S_ENABLE or S_DISABLE the WA procedure.
* @retval None.
*/
void SpiritRadioVcoCalibrationWAFB(SpiritFunctionalState xNewstate)
{
  xDoVcoCalibrationWA=xNewstate;
}

/**
* @brief  Returns the base carrier frequency.
* @param  None.
* @retval uint32_t Base carrier frequency expressed in Hz as unsigned word.
*/
uint32_t SpiritRadioGetFrequencyBase(void)
{
  uint32_t synthWord;
  BandSelect band;
  
  /* Reads the synth word */
  synthWord = SpiritRadioGetSynthWord();
  
  /* Reads the operating band */
  band = SpiritRadioGetBand();
  
  uint8_t cRefDiv = (uint8_t)SpiritRadioGetRefDiv() + 1;
  
  /* Calculates the frequency base and return it */
  return (uint32_t)round(synthWord*(((double)s_lXtalFrequency)/(FBASE_DIVIDER*cRefDiv*s_vectcBHalfFactor[band])));
}


/**
* @brief  Returns the actual channel center frequency.
* @param  None.
* @retval uint32_t Actual channel center frequency expressed in Hz.
*/
uint32_t SpiritRadioGetCenterFrequency(void)
{
  int32_t offset;
  uint8_t channel;
  uint32_t fBase;
  uint32_t channelSpace;
  
  /* Reads the frequency base */
  fBase = SpiritRadioGetFrequencyBase();
  
  /* Reads the frequency offset */
  offset = SpiritRadioGetFrequencyOffset();
  
  /* Reads the channel space */
  channelSpace = SpiritRadioGetChannelSpace();
  
  /* Reads the channel number */
  channel = SpiritRadioGetChannel();
  
  /* Calculates the channel center frequency and return it */
  return (uint32_t)(fBase +  offset + (uint32_t)(channelSpace*channel));
  
}


/**
* @brief  Returns the mantissa and exponent, whose value used in the datarate formula
*         will give the datarate value closer to the given datarate.
* @param  fDatarate datarate expressed in bps. This parameter ranging between 100 and 500000.
* @param  pcM pointer to the returned mantissa value.
* @param  pcE pointer to the returned exponent value.
* @retval None.
*/
void SpiritRadioSearchDatarateME(uint32_t lDatarate, uint8_t* pcM, uint8_t* pcE)
{
  volatile SpiritBool find = S_FALSE;
  int8_t i=15;
  uint8_t cMantissaTmp;
  uint8_t cDivider = 0;
  
  /* Check the parameters */
  s_assert_param(IS_DATARATE(lDatarate));
  
  cDivider = (uint8_t)SpiritRadioGetDigDiv();
  
  /* Search in the datarate array the exponent value */
  while(!find && i>=0)
  {
    if(lDatarate>=(s_lXtalFrequency>>(20-i+cDivider)))
    {
      find = S_TRUE;
    }
    else
    {
      i--;
    }
  }
  i<0 ? i=0 : i;
  *pcE = i;
  
  /* Calculates the mantissa value according to the datarate formula */
  cMantissaTmp = (lDatarate*((uint32_t)1<<(23-i)))/(s_lXtalFrequency>>(5+cDivider))-256;
  
  /* Finds the mantissa value with less approximation */
  int16_t mantissaCalculation[3];
  for(uint8_t j=0;j<3;j++)
  {
    if((cMantissaTmp+j-1))
    {
      mantissaCalculation[j]=lDatarate-(((256+cMantissaTmp+j-1)*(s_lXtalFrequency>>(5+cDivider)))>>(23-i));
    }
    else
    {
      mantissaCalculation[j]=0x7FFF;
    }
  }
  uint16_t mantissaCalculationDelta = 0xFFFF;
  for(uint8_t j=0;j<3;j++)
  {
    if(S_ABS(mantissaCalculation[j])<mantissaCalculationDelta)
    {
      mantissaCalculationDelta = S_ABS(mantissaCalculation[j]);
      *pcM = cMantissaTmp+j-1;
    }
  }
  
}


/**
* @brief  Returns the mantissa and exponent for a given bandwidth.
*         Even if it is possible to pass as parameter any value in the below mentioned range,
*         the API will search the closer value according to a fixed table of channel
*         bandwidth values (@ref s_vectnBandwidth), as defined in the datasheet, returning the corresponding mantissa
*         and exponent value.
* @param  lBandwidth bandwidth expressed in Hz. This parameter ranging between 1100 and 800100.
* @param  pcM pointer to the returned mantissa value.
* @param  pcE pointer to the returned exponent value.
* @retval None.
*/
void SpiritRadioSearchChannelBwME(uint32_t lBandwidth, uint8_t* pcM, uint8_t* pcE)
{
  int8_t i, i_tmp;
  uint8_t cDivider = 1;
  
    /* Search in the channel filter bandwidth table the exponent value */
  if(SpiritRadioGetDigDiv())
  {
    cDivider = 2;
  }
  else
  {
    cDivider = 1;
  }
    
  s_assert_param(IS_CH_BW(lBandwidth,s_lXtalFrequency/cDivider));
  
  uint32_t lChfltFactor = (s_lXtalFrequency/cDivider)/100;
  
  for(i=0;i<90 && (lBandwidth<(uint32_t)((s_vectnBandwidth26M[i]*lChfltFactor)/2600));i++);
  
  if(i!=0)
  {
    /* Finds the mantissa value with less approximation */
    i_tmp=i;
    int16_t chfltCalculation[3];
    for(uint8_t j=0;j<3;j++) 
    {
      if(((i_tmp+j-1)>=0) || ((i_tmp+j-1)<=89))
      {
        chfltCalculation[j] = lBandwidth - (uint32_t)((s_vectnBandwidth26M[i_tmp+j-1]*lChfltFactor)/2600);
      }
      else
      {
        chfltCalculation[j] = 0x7FFF;
      }
    }
    uint16_t chfltDelta = 0xFFFF;
    
    for(uint8_t j=0;j<3;j++)
    {
      if(S_ABS(chfltCalculation[j])<chfltDelta)
      {
        chfltDelta = S_ABS(chfltCalculation[j]);
        i=i_tmp+j-1;
      }    
    }
  }
  (*pcE) = (uint8_t)(i/9);
  (*pcM) = (uint8_t)(i%9);
  
}

/**
* @brief  Returns the mantissa and exponent, whose value used in the frequency deviation formula
*         will give a frequency deviation value most closer to the given frequency deviation.
* @param  fFDev frequency deviation expressed in Hz. This parameter can be a value in the range [F_Xo*8/2^18, F_Xo*7680/2^18].
* @param  pcM pointer to the returned mantissa value.
* @param  pcE pointer to the returned exponent value.
* @retval None.
*/
void SpiritRadioSearchFreqDevME(uint32_t lFDev, uint8_t* pcM, uint8_t* pcE)
{
  uint8_t i;
  uint32_t a,bp,b=0;
  float xtalDivtmp=(float)s_lXtalFrequency/(((uint32_t)1)<<18);
  
  /* Check the parameters */
  s_assert_param(IS_F_DEV(lFDev,s_lXtalFrequency));
  
  for(i=0;i<10;i++)
  {
    a=(uint32_t)(xtalDivtmp*(uint32_t)(7.5*(1<<i)));
    if(lFDev<a)
      break;
  }
  (*pcE) = i;
  
  for(i=0;i<8;i++)
  {
    bp=b;
    b=(uint32_t)(xtalDivtmp*(uint32_t)((8.0+i)/2*(1<<(*pcE))));
    if(lFDev<b)
      break;
  }
  
  (*pcM)=i;
  if((lFDev-bp)<(b-lFDev))
    (*pcM)--;
  
}


/**
* @brief  Sets the datarate.
* @param  fDatarate datarate expressed in bps. This value shall be in the range
*         [100 500000].
* @retval None.
*/
void SpiritRadioSetDatarate(uint32_t lDatarate)
{
  uint8_t drE, tempRegValue[2];
  
  /* Check the parameters */
  s_assert_param(IS_DATARATE(lDatarate));
  
  /* Calculates the datarate mantissa and exponent */
  SpiritRadioSearchDatarateME(lDatarate, &tempRegValue[0], &drE);
  
  /* Reads the MOD_O register*/
  SpiritSpiReadRegisters(MOD0_BASE, 1, &tempRegValue[1]);
  
  /* Mask the other fields and set the datarate exponent */
  tempRegValue[1] &= 0xF0;
  tempRegValue[1] |= drE;
  
  /* Writes the Datarate registers */
  g_xStatus = SpiritSpiWriteRegisters(MOD1_BASE, 2, tempRegValue);
  
}


/**
* @brief  Returns the datarate.
* @param  None.
* @retval uint32_t Settled datarate expressed in bps.
*/
uint32_t SpiritRadioGetDatarate(void)
{
  uint8_t tempRegValue[2];
  uint8_t cDivider=0;
  
  /* Reads the datarate registers for mantissa and exponent */
  g_xStatus = SpiritSpiReadRegisters(MOD1_BASE, 2, tempRegValue);
  
  /* Calculates the datarate */
  cDivider = (uint8_t)SpiritRadioGetDigDiv(); 
  
  return (((s_lXtalFrequency>>(5+cDivider))*(256+tempRegValue[0]))>>(23-(tempRegValue[1]&0x0F)));
}


/**
* @brief  Sets the frequency deviation.
* @param  fFDev frequency deviation expressed in Hz. Be sure that this value
*         is in the correct range [F_Xo*8/2^18, F_Xo*7680/2^18] Hz.
* @retval None.
*/
void SpiritRadioSetFrequencyDev(uint32_t lFDev)
{
  uint8_t FDevM, FDevE, tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_F_DEV(lFDev, s_lXtalFrequency));
  
  /* Calculates the frequency deviation mantissa and exponent */
  SpiritRadioSearchFreqDevME(lFDev, &FDevM, &FDevE);
  
  /* Reads the FDEV0 register */
  SpiritSpiReadRegisters(FDEV0_BASE, 1, &tempRegValue);
  
  /* Mask the other fields and set the frequency deviation mantissa and exponent */
  tempRegValue &= 0x08;
  tempRegValue |= ((FDevE<<4)|(FDevM));
  
  /* Writes the Frequency deviation register */
  g_xStatus = SpiritSpiWriteRegisters(FDEV0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the frequency deviation.
* @param  None.
* @retval uint32_t Frequency deviation value expressed in Hz.
*         This value will be in the range [F_Xo*8/2^18, F_Xo*7680/2^18] Hz.
*/
uint32_t SpiritRadioGetFrequencyDev(void)
{
  uint8_t tempRegValue, FDevM, FDevE;  

  
  /* Reads the frequency deviation register for mantissa and exponent */
  g_xStatus = SpiritSpiReadRegisters(FDEV0_BASE, 1, &tempRegValue);
  FDevM = tempRegValue&0x07;
  FDevE = (tempRegValue&0xF0)>>4;
  
  /* Calculates the frequency deviation and return it */
  //return (((s_lXtalFrequency>>6)*(8+FDevM))>>(13-FDevE));
  
  return (uint32_t)((float)s_lXtalFrequency/(((uint32_t)1)<<18)*(uint32_t)((8.0+FDevM)/2*(1<<FDevE)));
   
}


/**
* @brief  Sets the channel filter bandwidth.
* @param  lBandwidth channel filter bandwidth expressed in Hz. This parameter shall be in the range [1100 800100]
*         Even if it is possible to pass as parameter any value in the above mentioned range,
*         the API will search the most closer value according to a fixed table of channel
*         bandwidth values (@ref s_vectnBandwidth), as defined in the datasheet. To verify the settled channel bandwidth
*         it is possible to use the SpiritRadioGetChannelBW() API.
* @retval None.
*/
void SpiritRadioSetChannelBW(uint32_t lBandwidth)
{
  uint8_t bwM, bwE, tempRegValue;
  
  /* Search in the channel filter bandwidth table the exponent value */
  if(SpiritRadioGetDigDiv())
  {
    s_assert_param(IS_CH_BW(lBandwidth,(s_lXtalFrequency/2)));
  }
  else
  {
    s_assert_param(IS_CH_BW(lBandwidth,(s_lXtalFrequency)));
  } 
  
  /* Calculates the channel bandwidth mantissa and exponent */
  SpiritRadioSearchChannelBwME(lBandwidth, &bwM, &bwE);
  tempRegValue = (bwM<<4)|(bwE);
  
  /* Writes the Channel filter register */
  g_xStatus = SpiritSpiWriteRegisters(CHFLT_BASE, 1, &tempRegValue);
  
}

/**
* @brief  Returns the channel filter bandwidth.
* @param  None.
* @retval uint32_t Channel filter bandwidth expressed in Hz.
*/
uint32_t SpiritRadioGetChannelBW(void)
{
  uint8_t tempRegValue, bwM, bwE;
  
  /* Reads the channel filter register for mantissa and exponent */
  g_xStatus = SpiritSpiReadRegisters(CHFLT_BASE, 1, &tempRegValue);
  bwM = (tempRegValue&0xF0)>>4;
  bwE = tempRegValue&0x0F;
  
  /* Reads the channel filter bandwidth from the look-up table and return it */
  return (uint32_t)(100.0*s_vectnBandwidth26M[bwM+(bwE*9)]*s_lXtalFrequency/26e6);
  
}


/**
* @brief  Sets the modulation type.
* @param  xModulation modulation to set.
*         This parameter shall be of type @ref ModulationSelect .
* @retval None.
*/
void SpiritRadioSetModulation(ModulationSelect xModulation)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_MODULATION_SELECTED(xModulation));
  
  /* Reads the modulation register */
  SpiritSpiReadRegisters(MOD0_BASE, 1, &tempRegValue);
  
  /* Mask the other fields and set the modulation type */
  tempRegValue &=0x8F;
  tempRegValue |= xModulation;
  
  /* Writes the modulation register */
  g_xStatus = SpiritSpiWriteRegisters(MOD0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the modulation type used.
* @param  None.
* @retval ModulationSelect Settled modulation type.
*/
ModulationSelect SpiritRadioGetModulation(void)
{
  uint8_t tempRegValue;
  
  /* Reads the modulation register MOD0*/
  g_xStatus = SpiritSpiReadRegisters(MOD0_BASE, 1, &tempRegValue);
  
  /* Return the modulation type */
  return (ModulationSelect)(tempRegValue&0x70);
  
}


/**
* @brief  Enables or Disables the Continuous Wave transmit mode.
* @param  xNewState new state for power ramping.
*         This parameter can be: S_ENABLE or S_DISABLE .
* @retval None.
*/
void SpiritRadioCWTransmitMode(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the modulation register MOD0 and mask the CW field */
  SpiritSpiReadRegisters(MOD0_BASE, 1, &tempRegValue);
  if(xNewState == S_ENABLE)
  {
    tempRegValue |=MOD0_CW;
  }
  else
  {
    tempRegValue &= (~MOD0_CW);
  }
  
  /* Writes the new value in the MOD0 register */
  g_xStatus = SpiritSpiWriteRegisters(MOD0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Sets the OOK Peak Decay.
* @param  xOokDecay Peak decay control for OOK.
*         This parameter shall be of type @ref OokPeakDecay .
* @retval None.
*/
void SpiritRadioSetOokPeakDecay(OokPeakDecay xOokDecay)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_OOK_PEAK_DECAY(xOokDecay));
  
  /* Reads the RSSI_FLT register */
  SpiritSpiReadRegisters(RSSI_FLT_BASE, 1, &tempRegValue);
  
  /* Mask the other fields and set OOK Peak Decay */
  tempRegValue &= 0xFC;
  tempRegValue |= xOokDecay;
  
  /* Writes the RSSI_FLT register to set the new OOK peak dacay value */
  g_xStatus = SpiritSpiWriteRegisters(RSSI_FLT_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the OOK Peak Decay.
* @param  None
* @retval OokPeakDecay Ook peak decay value.
*/
OokPeakDecay SpiritRadioGetOokPeakDecay(void)
{
  uint8_t tempRegValue;
  
  /* Reads the OOK peak decay register RSSI_FLT_BASE*/
  g_xStatus = SpiritSpiReadRegisters(RSSI_FLT_BASE, 1, &tempRegValue);
  
  /* Returns the OOK peak decay */
  return (OokPeakDecay) (tempRegValue & 0x03);
  
}

/**
* @brief  Returns the PA register value that corresponds to the passed dBm power.
* @param  lFbase Frequency base expressed in Hz.
* @param  fPowerdBm Desired power in dBm.
* @retval Register value as byte.
* @note The power interpolation curves used by this function have been extracted
*       by measurements done on the divisional evaluation boards.
*/
uint8_t SpiritRadioGetdBm2Reg(uint32_t lFBase, float fPowerdBm)
{
  uint8_t i=0;
  uint8_t j=0;
  float fReg;
  
  if(IS_FREQUENCY_BAND_HIGH(lFBase))
  {
    i=0;
    if(lFBase<900000000) i=1;// 868   
  }
  else if(IS_FREQUENCY_BAND_MIDDLE(lFBase))
  {
    i=2;
  }
  else if(IS_FREQUENCY_BAND_LOW(lFBase))
  {
    i=3;
  }
  else if(IS_FREQUENCY_BAND_VERY_LOW(lFBase))
  {
    i=4;
  }
  
  j=1;
  if(fPowerdBm>0 && 13.0/fPowerFactors[i][2]-fPowerFactors[i][3]/fPowerFactors[i][2]<fPowerdBm)
      j=0;
  else if(fPowerdBm<=0 && 40.0/fPowerFactors[i][2]-fPowerFactors[i][3]/fPowerFactors[i][2]>fPowerdBm)
      j=2;

  fReg=fPowerFactors[i][2*j]*fPowerdBm+fPowerFactors[i][2*j+1];
  
  if(fReg<1)
    fReg=1;
  else if(fReg>90) 
    fReg=90;
  
  return ((uint8_t)fReg);
}


/**
* @brief  Returns the dBm power that corresponds to the value of PA register.
* @param  lFbase Frequency base expressed in Hz.
* @param  cPowerReg Register value of the PA.
* @retval Power in dBm as float.
* @note The power interpolation curves used by this function have been extracted
*       by measurements done on the divisional evaluation boards.
*/
float SpiritRadioGetReg2dBm(uint32_t lFBase, uint8_t cPowerReg)
{
  uint8_t i=0;
  uint8_t j=0;
  float fPower;
  
  if(cPowerReg==0 || cPowerReg>90)
    return (-130.0);
  
  if(IS_FREQUENCY_BAND_HIGH(lFBase))
  {
    i=0;
    if(lFBase<900000000) i=1;// 868   
  }
  else if(IS_FREQUENCY_BAND_MIDDLE(lFBase))
  {
    i=2;
  }
  else if(IS_FREQUENCY_BAND_LOW(lFBase))
  {
    i=3;
  }
  else if(IS_FREQUENCY_BAND_VERY_LOW(lFBase))
  {
    i=4;
  }
  
  j=1;
  if(cPowerReg<13) j=0;
  else if(cPowerReg>40) j=2;
  
  fPower=(((float)cPowerReg)/fPowerFactors[i][2*j]-fPowerFactors[i][2*j+1]/fPowerFactors[i][2*j]);
  
  return fPower;
}

/**
* @brief  Configures the Power Amplifier Table and registers with value expressed in dBm.
* @param  cPALevelMaxIndex number of levels to set. This parameter shall be in the range [0:7].
* @param  cWidth step width expressed in terms of bit period units Tb/8.
*         This parameter shall be in the range [1:4].
* @param  xCLoad one of the possible value of the enum type PALoadCapacitor.
*         @arg LOAD_0_PF    No additional PA load capacitor
*         @arg LOAD_1_2_PF  1.2pF additional PA load capacitor
*         @arg LOAD_2_4_PF  2.4pF additional PA load capacitor
*         @arg LOAD_3_6_PF  3.6pF additional PA load capacitor
* @param  pfPAtabledBm pointer to an array of PA values in dbm between [-PA_LOWER_LIMIT: PA_UPPER_LIMIT] dbm.
*         The first element shall be the lower level (PA_LEVEL[0]) value and the last element
*         the higher level one (PA_LEVEL[paLevelMaxIndex]).
* @retval None.
*/
void SpiritRadioSetPATabledBm(uint8_t cPALevelMaxIndex, uint8_t cWidth, PALoadCapacitor xCLoad, float* pfPAtabledBm)
{
  uint8_t palevel[9], address, paLevelValue;
  uint32_t lFBase=SpiritRadioGetFrequencyBase();

  /* Check the parameters */
  s_assert_param(IS_PA_MAX_INDEX(cPALevelMaxIndex));
  s_assert_param(IS_PA_STEP_WIDTH(cWidth));
  s_assert_param(IS_PA_LOAD_CAP(xCLoad));
  
  /* Check the PA level in dBm is in the range and calculate the PA_LEVEL value
  to write in the corresponding register using the linearization formula */
  for(int i=0; i<=cPALevelMaxIndex; i++)
  {
    s_assert_param(IS_PAPOWER_DBM(*pfPAtabledBm));
    paLevelValue=SpiritRadioGetdBm2Reg(lFBase,(*pfPAtabledBm));
    palevel[cPALevelMaxIndex-i]=paLevelValue;
    pfPAtabledBm++;
  }
  
  /* Sets the PA_POWER[0] register */
  palevel[cPALevelMaxIndex+1]=xCLoad|(cWidth-1)<<3|cPALevelMaxIndex;
  
  /* Sets the base address */
  address=PA_POWER8_BASE+7-cPALevelMaxIndex;
  
  /* Configures the PA_POWER registers */
  g_xStatus = SpiritSpiWriteRegisters(address, cPALevelMaxIndex+2, palevel);
  
}


/**
* @brief  Returns the Power Amplifier Table and registers, returning values in dBm.
* @param  pcPALevelMaxIndex pointer to the number of levels settled.
*         This parameter will be in the range [0:7].
* @param  pfPAtabledBm pointer to an array of 8 elements containing the PA value in dbm.
*         The first element will be the PA_LEVEL_0 and the last element
*         will be PA_LEVEL_7. Any value higher than PA_UPPER_LIMIT implies no output
*         power (output stage is in high impedance).
* @retval None.
*/
void SpiritRadioGetPATabledBm(uint8_t* pcPALevelMaxIndex, float* pfPAtabledBm)
{
  uint8_t palevelvect[9];
  uint32_t lFBase=SpiritRadioGetFrequencyBase();
  
  /* Reads the PA_LEVEL_x registers and the PA_POWER_0 register */
  g_xStatus = SpiritSpiReadRegisters(PA_POWER8_BASE, 9, palevelvect);
  
  /* Fill the PAtable */
  for(int i=7; i>=0; i--)
  {
    (*pfPAtabledBm)=SpiritRadioGetReg2dBm(lFBase,palevelvect[i]);
    pfPAtabledBm++;
  }
  
  /* Return the settled index */
  *pcPALevelMaxIndex = palevelvect[8]&0x07;
  
}






/**
* @brief  Sets a specific PA_LEVEL register, with a value given in dBm.
* @param  cIndex PA_LEVEL to set. This parameter shall be in the range [0:7].
* @param  fPowerdBm PA value to write expressed in dBm . Be sure that this values is in the
*         correct range [-PA_LOWER_LIMIT: PA_UPPER_LIMIT] dBm.
* @retval None.
* @note This function makes use of the @ref SpiritRadioGetdBm2Reg fcn to interpolate the 
*       power value.
*/
void SpiritRadioSetPALeveldBm(uint8_t cIndex, float fPowerdBm)
{
  uint8_t address, paLevelValue;
  
  /* Check the parameters */
  s_assert_param(IS_PA_MAX_INDEX(cIndex));
  s_assert_param(IS_PAPOWER_DBM(fPowerdBm));
  
  /* interpolate the power level */
  paLevelValue=SpiritRadioGetdBm2Reg(SpiritRadioGetFrequencyBase(),fPowerdBm);

  /* Sets the base address */
  address=PA_POWER8_BASE+7-cIndex;
  
  /* Configures the PA_LEVEL register */
  g_xStatus = SpiritSpiWriteRegisters(address, 1, &paLevelValue);
  
}


/**
* @brief  Returns a specific PA_LEVEL register, returning a value in dBm.
* @param  cIndex PA_LEVEL to read. This parameter shall be in the range [0:7]
* @retval float Settled power level expressed in dBm. A value
*         higher than PA_UPPER_LIMIT dBm implies no output power
*         (output stage is in high impedance).
* @note This function makes use of the @ref SpiritRadioGetReg2dBm fcn to interpolate the 
*       power value.
*/
float SpiritRadioGetPALeveldBm(uint8_t cIndex)
{
  uint8_t address, paLevelValue;
  
  /* Check the parameters */
  s_assert_param(IS_PA_MAX_INDEX(cIndex));
  
  /* Sets the base address */
  address=PA_POWER8_BASE+7-cIndex;
  
  /* Reads the PA_LEVEL[cIndex] register */
  g_xStatus = SpiritSpiReadRegisters(address, 1, &paLevelValue);
  
  return SpiritRadioGetReg2dBm(SpiritRadioGetFrequencyBase(),paLevelValue);
}


/**
* @brief  Configures the Power Amplifier Table and registers.
* @param  cPALevelMaxIndex number of levels to set. This parameter shall be in the range [0:7].
* @param  cWidth step width expressed in terms of bit period units Tb/8.
*         This parameter shall be in the range [1:4].
* @param  xCLoad one of the possible value of the enum type PALoadCapacitor.
*         @arg LOAD_0_PF    No additional PA load capacitor
*         @arg LOAD_1_2_PF  1.2pF additional PA load capacitor
*         @arg LOAD_2_4_PF  2.4pF additional PA load capacitor
*         @arg LOAD_3_6_PF  3.6pF additional PA load capacitor
* @param  pcPAtable pointer to an array of PA values in the range [0: 90], where 0 implies no
*         output power, 1 will be the maximum level and 90 the minimum one
*         The first element shall be the lower level (PA_LEVEL[0]) value and the last element
*         the higher level one (PA_LEVEL[paLevelMaxIndex]).
* @retval None.
*/
void SpiritRadioSetPATable(uint8_t cPALevelMaxIndex, uint8_t cWidth, PALoadCapacitor xCLoad, uint8_t* pcPAtable)
{
  uint8_t palevel[9], address;
  
  /* Check the parameters */
  s_assert_param(IS_PA_MAX_INDEX(cPALevelMaxIndex));
  s_assert_param(IS_PA_STEP_WIDTH(cWidth));
  s_assert_param(IS_PA_LOAD_CAP(xCLoad));
  
  /* Check the PA levels are in the range */
  for(int i=0; i<=cPALevelMaxIndex; i++)
  {
    s_assert_param(IS_PAPOWER(*pcPAtable));
    palevel[cPALevelMaxIndex-i]=*pcPAtable;
    pcPAtable++;
  }
  
  /* Sets the PA_POWER[0] register */
  palevel[cPALevelMaxIndex+1]=xCLoad|((cWidth-1)<<3)|cPALevelMaxIndex;
  
  /* Sets the base address */
  address=PA_POWER8_BASE+7-cPALevelMaxIndex;
  
  /* Configures the PA_POWER registers */
  g_xStatus = SpiritSpiWriteRegisters(address, cPALevelMaxIndex+2, palevel);
  
}


/**
* @brief  Returns the Power Amplifier Table and registers.
* @param  pcPALevelMaxIndex pointer to the number of levels settled.
*         This parameter shall be in the range [0:7].
* @param  pcPAtable pointer to an array of 8 elements containing the PA value.
*         The first element will be the PA_LEVEL_0 and the last element
*         will be PA_LEVEL_7. Any value equals to 0 implies that level has
*         no output power (output stage is in high impedance).
* @retval None
*/
void SpiritRadioGetPATable(uint8_t* pcPALevelMaxIndex, uint8_t* pcPAtable)
{
  uint8_t palevelvect[9];
  
  /* Reads the PA_LEVEL_x registers and the PA_POWER_0 register */
  g_xStatus = SpiritSpiReadRegisters(PA_POWER8_BASE, 9, palevelvect);
  
  /* Fill the PAtable */
  for(int i=7; i>=0; i--)
  {
    *pcPAtable = palevelvect[i];
    pcPAtable++;
  }
  
  /* Return the settled index */
  *pcPALevelMaxIndex = palevelvect[8]&0x07;
  
}


/**
* @brief  Sets a specific PA_LEVEL register.
* @param  cIndex PA_LEVEL to set. This parameter shall be in the range [0:7].
* @param  cPower PA value to write in the register. Be sure that this values is in the
*         correct range [0 : 90].
* @retval None.
*/
void SpiritRadioSetPALevel(uint8_t cIndex, uint8_t cPower)
{
  uint8_t address;
  
  /* Check the parameters */
  s_assert_param(IS_PA_MAX_INDEX(cIndex));
  s_assert_param(IS_PAPOWER(cPower));
  
  /* Sets the base address */
  address=PA_POWER8_BASE+7-cIndex;
  
  /* Configures the PA_LEVEL register */
  g_xStatus = SpiritSpiWriteRegisters(address, 1, &cPower);
  
}


/**
* @brief  Returns a specific PA_LEVEL register.
* @param  cIndex PA_LEVEL to read. This parameter shall be in the range [0:7].
* @retval uint8_t PA_LEVEL value. A value equal to zero
*         implies no output power (output stage is in high impedance).
*/
uint8_t SpiritRadioGetPALevel(uint8_t cIndex)
{
  uint8_t address, tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_PA_MAX_INDEX(cIndex));
  
  /* Sets the base address */
  address=PA_POWER8_BASE+7-cIndex;
  
  /* Reads the PA_LEVEL[cIndex] register and return the value */
  g_xStatus = SpiritSpiReadRegisters(address, 1, &tempRegValue);
  return tempRegValue;
  
}


/**
* @brief  Sets the output stage additional load capacitor bank.
* @param  xCLoad one of the possible value of the enum type PALoadCapacitor.
*         @arg LOAD_0_PF    No additional PA load capacitor
*         @arg LOAD_1_2_PF  1.2pF additional PA load capacitor
*         @arg LOAD_2_4_PF  2.4pF additional PA load capacitor
*         @arg LOAD_3_6_PF  3.6pF additional PA load capacitor
* @retval None.
*/
void SpiritRadioSetPACwc(PALoadCapacitor xCLoad)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_PA_LOAD_CAP(xCLoad));
  
  /* Reads the PA_POWER_0 register */
  SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
  /* Mask the CWC[1:0] field and write the new value */
  tempRegValue &= 0x3F;
  tempRegValue |= xCLoad;
  
  /* Configures the PA_POWER_0 register */
  g_xStatus = SpiritSpiWriteRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the output stage additional load capacitor bank.
* @param  None.
* @retval PALoadCapacitor Output stage additional load capacitor bank.
*         This parameter can be:
*         @arg LOAD_0_PF    No additional PA load capacitor
*         @arg LOAD_1_2_PF  1.2pF additional PA load capacitor
*         @arg LOAD_2_4_PF  2.4pF additional PA load capacitor
*         @arg LOAD_3_6_PF  3.6pF additional PA load capacitor
*/
PALoadCapacitor SpiritRadioGetPACwc(void)
{
  uint8_t tempRegValue;
  
  /* Reads the PA_POWER_0 register */
  g_xStatus = SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
  /* Mask the CWC[1:0] field and return the value*/
  return (PALoadCapacitor)(tempRegValue & 0xC0);
  
}


/**
* @brief  Sets a specific PA_LEVEL_MAX_INDEX.
* @param  cIndex PA_LEVEL_MAX_INDEX to set. This parameter shall be in the range [0:7].
* @retval None
*/
void SpiritRadioSetPALevelMaxIndex(uint8_t cIndex)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_PA_MAX_INDEX(cIndex));
  
  /* Reads the PA_POWER_0 register */
  SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
  /* Mask the PA_LEVEL_MAX_INDEX[1:0] field and write the new value */
  tempRegValue &= 0xF8;
  tempRegValue |= cIndex;
  
  /* Configures the PA_POWER_0 register */
  g_xStatus = SpiritSpiWriteRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the actual PA_LEVEL_MAX_INDEX.
* @param  None.
* @retval uint8_t Actual PA_LEVEL_MAX_INDEX. This parameter will be in the range [0:7].
*/
uint8_t SpiritRadioGetPALevelMaxIndex(void)
{
  uint8_t tempRegValue;
  
  /* Reads the PA_POWER_0 register */
  g_xStatus = SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
  /* Mask the PA_LEVEL_MAX_INDEX[1:0] field and return the value */
  return (tempRegValue & 0x07);
  
}


/**
* @brief  Sets a specific PA_RAMP_STEP_WIDTH.
* @param  cWidth step width expressed in terms of bit period units Tb/8.
*         This parameter shall be in the range [1:4].
* @retval None.
*/
void SpiritRadioSetPAStepWidth(uint8_t cWidth)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_PA_STEP_WIDTH(cWidth));
  
  /* Reads the PA_POWER_0 register */
  SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
  /* Mask the PA_RAMP_STEP_WIDTH[1:0] field and write the new value */
  tempRegValue &= 0xE7;
  tempRegValue |= (cWidth-1)<<3;
  
  /* Configures the PA_POWER_0 register */
  g_xStatus = SpiritSpiWriteRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the actual PA_RAMP_STEP_WIDTH.
* @param  None.
* @retval uint8_t Step width value expressed in terms of bit period units Tb/8.
*         This parameter will be in the range [1:4].
*/
uint8_t SpiritRadioGetPAStepWidth(void)
{
  uint8_t tempRegValue;
  
  /* Reads the PA_POWER_0 register */
  g_xStatus = SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
  /* Mask the PA_RAMP_STEP_WIDTH[1:0] field and return the value */
  tempRegValue &= 0x18;
  return  ((tempRegValue>>3)+1);
  
}


/**
* @brief  Enables or Disables the Power Ramping.
* @param  xNewState new state for power ramping.
*         This parameter can be: S_ENABLE or S_DISABLE.
* @retval None.
*/
void SpiritRadioPARamping(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the PA_POWER_0 register and configure the PA_RAMP_ENABLE field */
  SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= PA_POWER0_PA_RAMP_MASK;
  }
  else
  {
    tempRegValue &= (~PA_POWER0_PA_RAMP_MASK);
  }
  
  /* Sets the PA_POWER_0 register */
  g_xStatus = SpiritSpiWriteRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
}

/**
* @brief  Returns the Power Ramping enable bit.
* @param  xNewState new state for power ramping.
*         This parameter can be: S_ENABLE or S_DISABLE.
* @retval None.
*/
SpiritFunctionalState SpiritRadioGetPARamping(void)
{
  uint8_t tempRegValue;
  
  /* Reads the PA_POWER_0 register and configure the PA_RAMP_ENABLE field */
  g_xStatus = SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue);
  
  /* Mask and return data */
  return (SpiritFunctionalState)((tempRegValue>>5) & 0x01);
  
}


/**
* @brief  Enables or Disables the AFC.
* @param  xNewState new state for AFC.
*         This parameter can be: S_ENABLE or S_DISABLE.
* @retval None.
*/
void SpiritRadioAFC(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the AFC_2 register and configure the AFC Enabled field */
  SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue);
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= AFC2_AFC_MASK;
  }
  else
  {
    tempRegValue &= (~AFC2_AFC_MASK);
  }
  
  /* Sets the AFC_2 register */
  g_xStatus = SpiritSpiWriteRegisters(AFC2_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Enables or Disables the AFC freeze on sync word detection.
* @param  xNewState new state for AFC freeze on sync word detection.
*         This parameter can be: S_ENABLE or S_DISABLE.
* @retval None.
*/
void SpiritRadioAFCFreezeOnSync(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the AFC_2 register and configure the AFC Freeze on Sync field */
  SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue);
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= AFC2_AFC_FREEZE_ON_SYNC_MASK;
  }
  else
  {
    tempRegValue &= (~AFC2_AFC_FREEZE_ON_SYNC_MASK);
  }
  
  /* Sets the AFC_2 register */
  g_xStatus = SpiritSpiWriteRegisters(AFC2_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Sets the AFC working mode.
* @param  xMode the AFC mode. This parameter can be one of the values defined in @ref AFCMode :
*         @arg AFC_SLICER_CORRECTION     AFC loop closed on slicer
*         @arg AFC_2ND_IF_CORRECTION     AFC loop closed on 2nd conversion stage
* @retval None.
*/
void SpiritRadioSetAFCMode(AFCMode xMode)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_AFC_MODE(xMode));
  
  /* Reads the AFC_2 register and configure the AFC Mode field */
  SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue);
  if(xMode == AFC_2ND_IF_CORRECTION)
  {
    tempRegValue |= AFC_2ND_IF_CORRECTION;
  }
  else
  {
    tempRegValue &= (~AFC_2ND_IF_CORRECTION);
  }
  
  /* Sets the AFC_2 register */
  g_xStatus = SpiritSpiWriteRegisters(AFC2_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AFC working mode.
* @param  None.
* @retval AFCMode Settled AFC mode. This parameter will be one of the values defined in @ref AFCMode :
*         @arg AFC_SLICER_CORRECTION     AFC loop closed on slicer
*         @arg AFC_2ND_IF_CORRECTION     AFC loop closed on 2nd conversion stage
*/
AFCMode SpiritRadioGetAFCMode(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AFC_2 register */
  g_xStatus = SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue);
  
  /* Mask the AFC Mode field and returns the value */
  return (AFCMode)(tempRegValue & 0x20);
  
}


/**
* @brief  Sets the AFC peak detector leakage.
* @param  cLeakage the peak detector leakage. This parameter shall be in the range:
*         [0:31].
* @retval None.
*/
void SpiritRadioSetAFCPDLeakage(uint8_t cLeakage)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_AFC_PD_LEAKAGE(cLeakage));
  
  /* Reads the AFC_2 register and configure the AFC PD leakage field */
  SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue);
  tempRegValue &= 0xE0;
  tempRegValue |= cLeakage;
  
  /* Sets the AFC_2 register */
  g_xStatus = SpiritSpiWriteRegisters(AFC2_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AFC peak detector leakage.
* @param  None.
* @retval uint8_t Peak detector leakage value. This parameter will be in the range:
*         [0:31].
*/
uint8_t SpiritRadioGetAFCPDLeakage(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AFC_2 register */
  g_xStatus = SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue);
  
  /* Mask the AFC PD leakage field and return the value */
  return (tempRegValue & 0x1F);
  
}


/**
* @brief  Sets the length of the AFC fast period expressed as number of samples.
* @param  cLength length of the fast period in number of samples.
* @retval None.
*/
void SpiritRadioSetAFCFastPeriod(uint8_t cLength)
{
  /* Sets the AFC_1 register */
  g_xStatus = SpiritSpiWriteRegisters(AFC1_BASE, 1, &cLength);
  
}


/**
* @brief  Returns the AFC fast period expressed as number of samples.
* @param  None.
* @retval uint8_t Length of the fast period in number of samples.
*/
uint8_t SpiritRadioGetAFCFastPeriod(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AFC 1 register and return the value */
  g_xStatus = SpiritSpiReadRegisters(AFC1_BASE, 1, &tempRegValue);
  
  return tempRegValue;
  
}


/**
* @brief  Sets the AFC loop gain in fast mode.
* @param  cGain AFC loop gain in fast mode. This parameter shall be in the range:
*         [0:15].
* @retval None.
*/
void SpiritRadioSetAFCFastGain(uint8_t cGain)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_AFC_FAST_GAIN(cGain));
  
  /* Reads the AFC_0 register and configure the AFC Fast Gain field */
  SpiritSpiReadRegisters(AFC0_BASE, 1, &tempRegValue);
  tempRegValue &= 0x0F;
  tempRegValue |= cGain<<4;
  
  /* Sets the AFC_0 register */
  g_xStatus = SpiritSpiWriteRegisters(AFC0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AFC loop gain in fast mode.
* @param  None.
* @retval uint8_t AFC loop gain in fast mode. This parameter will be in the range:
*         [0:15].
*/
uint8_t SpiritRadioGetAFCFastGain(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AFC_0 register, mask the AFC Fast Gain field and return the value  */
  g_xStatus = SpiritSpiReadRegisters(AFC0_BASE, 1, &tempRegValue);
  
  return ((tempRegValue & 0xF0)>>4);
  
}


/**
* @brief  Sets the AFC loop gain in slow mode.
* @param  cGain AFC loop gain in slow mode. This parameter shall be in the range:
*         [0:15].
* @retval None.
*/
void SpiritRadioSetAFCSlowGain(uint8_t cGain)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_AFC_SLOW_GAIN(cGain));
  
  /* Reads the AFC_0 register and configure the AFC Slow Gain field */
  SpiritSpiReadRegisters(AFC0_BASE, 1, &tempRegValue);
  tempRegValue &= 0xF0;
  tempRegValue |= cGain;
  
  /* Sets the AFC_0 register */
  g_xStatus = SpiritSpiWriteRegisters(AFC0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AFC loop gain in slow mode.
* @param  None.
* @retval uint8_t AFC loop gain in slow mode. This parameter will be in the range:
*         [0:15].
*/
uint8_t SpiritRadioGetAFCSlowGain(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AFC_0 register, mask the AFC Slow Gain field and return the value */
  g_xStatus = SpiritSpiReadRegisters(AFC0_BASE, 1, &tempRegValue);
  
  return (tempRegValue & 0x0F);
  
}


/**
* @brief  Returns the AFC correction from the corresponding register.
* @param  None.
* @retval int8_t AFC correction, read from the corresponding register.
*         This parameter will be in the range [-128:127].
*/
int8_t SpiritRadioGetAFCCorrectionReg(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AFC_CORR register, cast the read value as signed char and return it */
  g_xStatus = SpiritSpiReadRegisters(AFC_CORR_BASE, 1, &tempRegValue);
  
  return (int8_t)tempRegValue;
  
}


/**
* @brief  Returns the AFC correction expressed in Hz.
* @param  None.
* @retval int32_t AFC correction expressed in Hz
*         according to the following formula:<ul>
*         <li> Fafc[Hz]= (Fdig/(12*2^10))*AFC_CORR  where </li>
*         <li> AFC_CORR is the value read in the AFC_CORR register </li> </ul>
*/
int32_t SpiritRadioGetAFCCorrectionHz(void)
{
  int8_t correction;
  uint32_t xtal = s_lXtalFrequency;
  
  /* Reads the AFC correction register */
  correction = SpiritRadioGetAFCCorrectionReg();
  
  if(xtal>DOUBLE_XTAL_THR)
  {
    xtal /= 2;
  }
  
  /* Calculates and return the Frequency Correction */
  return (int32_t)(xtal/(12*pow(2,10))*correction);
  
}


/**
* @brief  Enables or Disables the AGC.
* @param  xNewState new state for AGC.
*         This parameter can be: S_ENABLE or S_DISABLE
* @retval None.
*/
void SpiritRadioAGC(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the AGCCTRL_0 register and configure the AGC Enabled field */
  SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= AGCCTRL0_AGC_MASK;
  }
  else
  {
    tempRegValue &= (~AGCCTRL0_AGC_MASK);
  }
  
  /* Sets the AGCCTRL_0 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Sets the AGC working mode.
* @param  xMode the AGC mode. This parameter can be one of the values defined in @ref AGCMode :
*         @arg AGC_LINEAR_MODE     AGC works in linear mode
*         @arg AGC_BINARY_MODE     AGC works in binary mode
* @retval None.
*/
void SpiritRadioSetAGCMode(AGCMode xMode)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_AGC_MODE(xMode));
  
  /* Reads the AGCCTRL_0 register and configure the AGC Mode field */
  SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  if(xMode == AGC_BINARY_MODE)
  {
    tempRegValue |= AGC_BINARY_MODE;
  }
  else
  {
    tempRegValue &= (~AGC_BINARY_MODE);
  }
  
  /* Sets the AGCCTRL_0 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AGC working mode.
* @param  None.
* @retval AGCMode Settled AGC mode.  This parameter can be one of the values defined in @ref AGCMode :
*         @arg AGC_LINEAR_MODE     AGC works in linear mode
*         @arg AGC_BINARY_MODE     AGC works in binary mode
*/
AGCMode SpiritRadioGetAGCMode(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AGCCTRL_0 register, mask the AGC Mode field and return the value */
  g_xStatus = SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  
  return  (AGCMode)(tempRegValue & 0x40);
  
}


/**
* @brief  Enables or Disables the AGC freeze on steady state.
* @param  xNewState new state for AGC freeze on steady state.
*         This parameter can be: S_ENABLE or S_DISABLE.
* @retval None.
*/
void SpiritRadioAGCFreezeOnSteady(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the AGCCTRL_2 register and configure the AGC Freeze On Steady field */
  SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= AGCCTRL2_FREEZE_ON_STEADY_MASK;
  }
  else
  {
    tempRegValue &= (~AGCCTRL2_FREEZE_ON_STEADY_MASK);
  }
  
  /* Sets the AGCCTRL_2 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Enable or Disable the AGC freeze on sync detection.
* @param  xNewState new state for AGC freeze on sync detection.
*         This parameter can be: S_ENABLE or S_DISABLE.
* @retval None.
*/
void SpiritRadioAGCFreezeOnSync(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the AGCCTRL_2 register and configure the AGC Freeze On Sync field */
  SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= AGCCTRL2_FREEZE_ON_SYNC_MASK;
  }
  else
  {
    tempRegValue &= (~AGCCTRL2_FREEZE_ON_SYNC_MASK);
  }
  
  /* Sets the AGCCTRL_2 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Enable or Disable the AGC to start with max attenuation.
* @param  xNewState new state for AGC start with max attenuation mode.
*         This parameter can be: S_ENABLE or S_DISABLE.
* @retval None.
*/
void SpiritRadioAGCStartMaxAttenuation(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue = 0x00;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the AGCCTRL_2 register and configure the AGC Start Max Attenuation field */
  SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= AGCCTRL2_START_MAX_ATTENUATION_MASK;
  }
  else
  {
    tempRegValue &= (~AGCCTRL2_START_MAX_ATTENUATION_MASK);
  }
  
  /* Sets the AGCCTRL_2 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Sets the AGC measure time.
* @param  nTime AGC measure time expressed in us. This parameter shall be in the range [0, 393216/F_Xo].
* @retval None.
*/
void SpiritRadioSetAGCMeasureTimeUs(uint16_t nTime)
{
  uint8_t tempRegValue, measure;
  
  /* Check the parameter */
  s_assert_param(IS_AGC_MEASURE_TIME_US(nTime,s_lXtalFrequency));
  
  /* Reads the AGCCTRL_2 register */
  SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  
  /* Calculates the measure time value to write in the register */
  measure = (uint8_t)lroundf(log2((float)nTime/1e6 * s_lXtalFrequency/12));
  (measure>15) ? (measure=15):(measure);
  
  /* Mask the MEAS_TIME field and write the new value */
  tempRegValue &= 0xF0;
  tempRegValue |= measure;
  
  /* Sets the AGCCTRL_2 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AGC measure time.
* @param  None.
* @retval uint16_t AGC measure time expressed in us. This parameter will be in the range [0, 393216/F_Xo].
*/
uint16_t SpiritRadioGetAGCMeasureTimeUs(void)
{
  uint8_t measure;
  
  /* Reads the AGCCTRL_2 register */
  g_xStatus = SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &measure);
  
  /* Mask the MEAS_TIME field */
  measure &= 0x0F;
  
  /* Calculates the measure time value to write in the register */
  return (uint16_t)((12.0/s_lXtalFrequency)*(float)pow(2,measure)*1e6);
  
}


/**
* @brief  Sets the AGC measure time.
* @param  cTime AGC measure time to write in the MEAS_TIME field of AGCCTRL_2 register.
*         This parameter shall be in the range [0:15].
* @retval None.
*/
void SpiritRadioSetAGCMeasureTime(uint8_t cTime)
{
  uint8_t tempRegValue;
  
  /* Check the parameter */
  s_assert_param(IS_AGC_MEASURE_TIME(cTime));
  
  /* Reads the AGCCTRL_2 register */
  SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  
  /* Mask the MEAS_TIME field and write the new value */
  tempRegValue &= 0xF0;
  tempRegValue |= cTime;
  
  /* Sets the AGCCTRL_2 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AGC measure time.
* @param  None.
* @retval uint8_t AGC measure time read from the MEAS_TIME field of AGCCTRL_2 register.
*         This parameter will be in the range [0:15].
*/
uint8_t SpiritRadioGetAGCMeasureTime(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AGCCTRL_2 register, mask the MEAS_TIME field and return the value  */
  g_xStatus = SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue);
  
  return (tempRegValue & 0x0F);
  
}


/**
* @brief  Sets the AGC hold time.
* @param  cTime AGC hold time expressed in us. This parameter shall be in the range[0, 756/F_Xo].
* @retval None.
*/
void SpiritRadioSetAGCHoldTimeUs(uint8_t cTime)
{
  uint8_t tempRegValue, hold;
  
  /* Check the parameter */
  s_assert_param(IS_AGC_HOLD_TIME_US(cTime,s_lXtalFrequency));
  
  /* Reads the AGCCTRL_0 register */
  SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  
  /* Calculates the hold time value to write in the register */
  hold = (uint8_t)lroundf(((float)cTime/1e6 * s_lXtalFrequency)/12);
  (hold>63) ? (hold=63):(hold);
  
  /* Mask the HOLD_TIME field and write the new value */
  tempRegValue &= 0xC0;
  tempRegValue |= hold;
  
  /* Sets the AGCCTRL_0 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AGC hold time.
* @param  None.
* @retval uint8_t AGC hold time expressed in us. This parameter will be in the range:
*         [0, 756/F_Xo].
*/
uint8_t SpiritRadioGetAGCHoldTimeUs(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AGCCTRL_0 register */
  g_xStatus = SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  
  /* Mask the HOLD_TIME field */
  tempRegValue &= 0x3F;
  
  /* Calculates the hold time value and return it */
  return (uint8_t)lroundf ((12.0/s_lXtalFrequency)*(tempRegValue*1e6));
  
}


/**
* @brief  Sets the AGC hold time.
* @param  cTime AGC hold time to write in the HOLD_TIME field of AGCCTRL_0 register.
*         This parameter shall be in the range [0:63].
* @retval None.
*/
void SpiritRadioSetAGCHoldTime(uint8_t cTime)
{
  uint8_t tempRegValue;
  
  /* Check the parameter */
  s_assert_param(IS_AGC_HOLD_TIME(cTime));
  
  /* Reads the AGCCTRL_0 register */
  SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  
  /* Mask the HOLD_TIME field and write the new value */
  tempRegValue &= 0xC0;
  tempRegValue |= cTime;
  
  /* Sets the AGCCTRL_0 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AGC hold time.
* @param  None.
* @retval uint8_t AGC hold time read from the HOLD_TIME field of AGCCTRL_0 register.
*         This parameter will be in the range [0:63].
*/
uint8_t SpiritRadioGetAGCHoldTime(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AGCCTRL_0 register, mask the MEAS_TIME field and return the value  */
  g_xStatus = SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue);
  
  return (tempRegValue & 0x3F);
  
}


/**
* @brief  Sets the AGC high threshold.
* @param  cHighThreshold AGC high threshold to write in the THRESHOLD_HIGH field of AGCCTRL_1 register.
*         This parameter shall be in the range [0:15].
* @retval None.
*/
void SpiritRadioSetAGCHighThreshold(uint8_t cHighThreshold)
{
  uint8_t tempRegValue;
  
  /* Check the parameter */
  s_assert_param(IS_AGC_THRESHOLD(cHighThreshold));
  
  /* Reads the AGCCTRL_1 register */
  SpiritSpiReadRegisters(AGCCTRL1_BASE, 1, &tempRegValue);
  
  /* Mask the THRESHOLD_HIGH field and write the new value */
  tempRegValue &= 0x0F;
  tempRegValue |= cHighThreshold<<4;
  
  /* Sets the AGCCTRL_1 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL1_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AGC high threshold.
* @param  None.
* @retval uint8_t AGC high threshold read from the THRESHOLD_HIGH field of AGCCTRL_1 register.
*         This parameter will be in the range [0:15].
*/
uint8_t SpiritRadioGetAGCHighThreshold(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AGCCTRL_1 register, mask the THRESHOLD_HIGH field and return the value */
  g_xStatus = SpiritSpiReadRegisters(AGCCTRL1_BASE, 1, &tempRegValue);
  
  return ((tempRegValue & 0xF0)>>4);
  
}


/**
* @brief  Sets the AGC low threshold.
* @param  cLowThreshold AGC low threshold to write in the THRESHOLD_LOW field of AGCCTRL_1 register.
*         This parameter shall be in the range [0:15].
* @retval None.
*/
void SpiritRadioSetAGCLowThreshold(uint8_t cLowThreshold)
{
  uint8_t tempRegValue;
  
  /* Check the parameter */
  s_assert_param(IS_AGC_THRESHOLD(cLowThreshold));
  
  /* Reads the AGCCTRL_1 register */
  SpiritSpiReadRegisters(AGCCTRL1_BASE, 1, &tempRegValue);
  
  /* Mask the THRESHOLD_LOW field and write the new value */
  tempRegValue &= 0xF0;
  tempRegValue |= cLowThreshold;
  
  /* Sets the AGCCTRL_1 register */
  g_xStatus = SpiritSpiWriteRegisters(AGCCTRL1_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the AGC low threshold.
* @param  None.
* @retval uint8_t AGC low threshold read from the THRESHOLD_LOW field of AGCCTRL_1 register.
*         This parameter will be in the range [0:15].
*/
uint8_t SpiritRadioGetAGCLowThreshold(void)
{
  uint8_t tempRegValue;
  
  /* Reads the AGCCTRL_1 register, mask the THRESHOLD_LOW field and return the value  */
  g_xStatus = SpiritSpiReadRegisters(AGCCTRL1_BASE, 1, &tempRegValue);
  
  return (tempRegValue & 0x0F);
  
}


/**
* @brief  Sets the clock recovery algorithm.
* @param  xMode the Clock Recovery mode. This parameter can be one of the values defined in @ref ClkRecMode :
*         @arg CLK_REC_PLL     PLL alogrithm for clock recovery
*         @arg CLK_REC_DLL     DLL alogrithm for clock recovery
* @retval None.
*/
void SpiritRadioSetClkRecMode(ClkRecMode xMode)
{
  uint8_t tempRegValue;
  
  /* Check the parameter */
  s_assert_param(IS_CLK_REC_MODE(xMode));
  
  /* Reads the FDEV_0 register */
  SpiritSpiReadRegisters(FDEV0_BASE, 1, &tempRegValue);
  
  /* Mask the CLOCK_REC_ALGO_SEL field and write the new value */
  tempRegValue &= 0xF7;
  tempRegValue |= (uint8_t)xMode;
  
  /* Sets the FDEV_0 register */
  g_xStatus = SpiritSpiWriteRegisters(FDEV0_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the Clock Recovery working mode.
* @param  None.
* @retval ClkRecMode Clock Recovery mode. This parameter can be one of the values defined in @ref ClkRecMode :
*         @arg CLK_REC_PLL     PLL alogrithm for clock recovery
*         @arg CLK_REC_DLL     DLL alogrithm for clock recovery
*/
ClkRecMode SpiritRadioGetClkRecMode(void)
{
  uint8_t tempRegValue;
  
  /* Reads the FDEV_0 register, mask the CLOCK_REC_ALGO_SEL field and return the value */
  g_xStatus = SpiritSpiReadRegisters(FDEV0_BASE, 1, &tempRegValue);
  
  return (ClkRecMode)(tempRegValue & 0x08);
  
}


/**
* @brief  Sets the clock recovery proportional gain.
* @param  cPGain the Clock Recovery proportional gain to write in the CLK_REC_P_GAIN field of CLOCKREC register.
*         It represents is log2 value of the clock recovery proportional gain.
*          This parameter shall be in the range [0:7].
* @retval None.
*/
void SpiritRadioSetClkRecPGain(uint8_t cPGain)
{
  uint8_t tempRegValue;
  
  /* Check the parameter */
  s_assert_param(IS_CLK_REC_P_GAIN(cPGain));
  
  /* Reads the CLOCKREC register */
  SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue);
  
  /* Mask the CLK_REC_P_GAIN field and write the new value */
  tempRegValue &= 0x1F;
  tempRegValue |= (cPGain<<5);
  
  /* Sets the CLOCKREC register */
  g_xStatus = SpiritSpiWriteRegisters(CLOCKREC_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the log2 of the clock recovery proportional gain.
* @param  None.
* @retval uint8_t Clock Recovery proportional gain read from the CLK_REC_P_GAIN field of CLOCKREC register.
*         This parameter will be in the range [0:7].
*/
uint8_t SpiritRadioGetClkRecPGain(void)
{
  uint8_t tempRegValue;
  
  /* Reads the CLOCKREC register, mask the CLK_REC_P_GAIN field and return the value  */
  g_xStatus = SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue);
  
  return ((tempRegValue & 0xEF)>>5);
  
}


/**
* @brief  Sets the clock recovery integral gain.
* @param  cIGain the Clock Recovery integral gain to write in the CLK_REC_I_GAIN field of CLOCKREC register.
*         This parameter shall be in the range [0:15].
* @retval None.
*/
void SpiritRadioSetClkRecIGain(uint8_t cIGain)
{
  uint8_t tempRegValue;
  
  /* Check the parameter */
  s_assert_param(IS_CLK_REC_I_GAIN(cIGain));
  
  /* Reads the CLOCKREC register */
  SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue);
  
  /* Mask the CLK_REC_P_GAIN field and write the new value */
  tempRegValue &= 0xF0;
  tempRegValue |= cIGain;
  
  /* Sets the CLOCKREC register */
  g_xStatus = SpiritSpiWriteRegisters(CLOCKREC_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the clock recovery integral gain.
* @param  None.
* @retval uint8_t Clock Recovery integral gain read from the
*         CLK_REC_I_GAIN field of CLOCKREC register.
*         This parameter will be in the range [0:15].
*/
uint8_t SpiritRadioGetClkRecIGain(void)
{
  uint8_t tempRegValue;
  
  /* Reads the CLOCKREC register, mask the CLK_REC_I_GAIN field and return the value */
  g_xStatus = SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue);
  
  return (tempRegValue & 0x0F);
  
}


/**
* @brief  Sets the postfilter length for clock recovery algorithm.
* @param  xLength the postfilter length in symbols. This parameter can be one of the values defined in @ref PstFltLength :
*         @arg PSTFLT_LENGTH_8     Postfilter length is 8 symbols
*         @arg PSTFLT_LENGTH_16    Postfilter length is 16 symbols
* @retval None.
*/
void SpiritRadioSetClkRecPstFltLength(PstFltLength xLength)
{
  uint8_t tempRegValue;
  
  /* Check the parameter */
  s_assert_param(IS_PST_FLT_LENGTH(xLength));
  
  /* Reads the CLOCKREC register */
  SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue);
  
  /* Mask the PSTFLT_LEN field and write the new value */
  tempRegValue &= 0xEF;
  tempRegValue |= (uint8_t)xLength;
  
  /* Sets the CLOCKREC register */
  g_xStatus = SpiritSpiWriteRegisters(CLOCKREC_BASE, 1, &tempRegValue);
  
}


/**
* @brief  Returns the postfilter length for clock recovery algorithm.
* @param  None.
* @retval PstFltLength Postfilter length in symbols. This parameter can be one of the values defined in @ref PstFltLength :
*         @arg PSTFLT_LENGTH_8     Postfilter length is 8 symbols
*         @arg PSTFLT_LENGTH_16    Postfilter length is 16 symbols
*/
PstFltLength SpiritRadioGetClkRecPstFltLength(void)
{
  uint8_t tempRegValue;
  
  /* Reads the CLOCKREC register, mask the PSTFLT_LEN field and return the value */
  g_xStatus = SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue);
  
  return (PstFltLength)(tempRegValue & 0x10);
  
}


/**
* @brief  Enables or Disables the received data blanking when the CS is under the threshold.
* @param  xNewState new state of this mode.
*         This parameter can be: S_ENABLE or S_DISABLE .
* @retval None.
*/
void SpiritRadioCsBlanking(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the ANT_SELECT_CONF_BASE and mask the CS_BLANKING BIT field */
  SpiritSpiReadRegisters(ANT_SELECT_CONF_BASE, 1, &tempRegValue);
  
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= ANT_SELECT_CS_BLANKING_MASK;
  }
  else
  {
    tempRegValue &= (~ANT_SELECT_CS_BLANKING_MASK);
  }
  
  /* Writes the new value in the ANT_SELECT_CONF register */
  g_xStatus = SpiritSpiWriteRegisters(ANT_SELECT_CONF_BASE, 1, &tempRegValue);
  
  
}

/**
* @brief  Enables or Disables the persistent RX mode.
* @param  xNewState new state of this mode.
*         This parameter can be: S_ENABLE or S_DISABLE .
* @retval None.
*/
void SpiritRadioPersistenRx(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the PROTOCOL0_BASE and mask the PROTOCOL0_PERS_RX_MASK bitfield */
  SpiritSpiReadRegisters(PROTOCOL0_BASE, 1, &tempRegValue);
  
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= PROTOCOL0_PERS_RX_MASK;
  }
  else
  {
    tempRegValue &= (~PROTOCOL0_PERS_RX_MASK);
  }
  
  /* Writes the new value in the PROTOCOL0_BASE register */
  g_xStatus = SpiritSpiWriteRegisters(PROTOCOL0_BASE, 1, &tempRegValue);
  
}

/**
* @brief  Enables or Disables the synthesizer reference divider.
* @param  xNewState new state for synthesizer reference divider.
*         This parameter can be: S_ENABLE or S_DISABLE .
* @retval None.
*/
void SpiritRadioSetRefDiv(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the SYNTH_CONFIG1_BASE and mask the REFDIV bit field */
  SpiritSpiReadRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue);
  
  if(xNewState == S_ENABLE)
  {
    tempRegValue |= 0x80;
  }
  else
  {
    tempRegValue &= 0x7F;
  }
  
  /* Writes the new value in the SYNTH_CONFIG1_BASE register */
  g_xStatus = SpiritSpiWriteRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue);
  
}

/**
* @brief  Get the the synthesizer reference divider state.
* @param  void.
* @retval None.
*/


SpiritFunctionalState SpiritRadioGetRefDiv(void)
{
  uint8_t tempRegValue;
  
  g_xStatus = SpiritSpiReadRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue);
  
  //값을 읽어 왔을때, Reserved 영역의 니블 값이 1011 임.
  int iMask = 1;
  
  printf("\n !!!!!!!!!!!\n");
    for (int i = 8; i > 0; --i)
    {        
        //값 찍기
        printf("%d",(tempRegValue & (iMask << i-1))?1:0);
    }
  printf("\n !!!!!!!!!!!\n");
  
  
  
  
  
  
  
  
  if(((tempRegValue>>7)&0x1))
  {
    return S_ENABLE;
  }
  else
  {
    return S_DISABLE;
  }
  
}

/**
* @brief  Enables or Disables the synthesizer reference divider.
* @param  xNewState new state for synthesizer reference divider.
*         This parameter can be: S_ENABLE or S_DISABLE .
* @retval None.
*/
void SpiritRadioSetDigDiv(SpiritFunctionalState xNewState)
{
  uint8_t tempRegValue;
  
  /* Check the parameters */
  s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState));
  
  /* Reads the XO_RCO_TEST_BASE and mask the PD_CLKDIV bit field */
  SpiritSpiReadRegisters(XO_RCO_TEST_BASE, 1, &tempRegValue);
  
  if(xNewState == S_ENABLE)
  {
    tempRegValue &= 0xf7;
  }
  else
  {
    
    tempRegValue |= 0x08;
  }
  
  /* Writes the new value in the XO_RCO_TEST_BASE register */
  g_xStatus = SpiritSpiWriteRegisters(XO_RCO_TEST_BASE, 1, &tempRegValue);
  
}

/**
* @brief  Get the the synthesizer reference divider state.
* @param  void.
* @retval None.
*/
SpiritFunctionalState SpiritRadioGetDigDiv(void)
{
  uint8_t tempRegValue;
  
  g_xStatus = SpiritSpiReadRegisters(XO_RCO_TEST_BASE, 1, &tempRegValue);
  
  if(((tempRegValue>>3)&0x1))
  {
    return S_DISABLE;
  }
  else
  {
    return S_ENABLE;
  }
  
}

/**
* @brief  Returns the XTAL frequency.
* @param  void.
* @retval uint32_t XTAL frequency.
*/
uint32_t SpiritRadioGetXtalFrequency(void)
{
  return s_lXtalFrequency; 
}

/**
* @brief  Sets the XTAL frequency.
* @param  uint32_t XTAL frequency.
* @retval void.
*/
void SpiritRadioSetXtalFrequency(uint32_t lXtalFrequency)
{
  s_lXtalFrequency = lXtalFrequency; 
}

/**
* @}
*/


/**
* @}
*/


/**
* @}
*/



/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/

