/*****************************************************************************
* File Name          : BC45_Function.c
* Author             : CrystalSu
* Version            : V1.0.0.0
* Date               : Feb 12, 2020
* Description        : For using Card Detection Feature.
******************************************************************************/

#include "BC45_Function.h"
#include "BC45_Chip_Function.h"
#include "htk_uart.h"
#include "htk_spi.h"

/* Private Variable */
uint8_t DataResponse[8];
uint8_t DataTransfer[8];
uint16_t DataTransLen;
uint16_t DataRespLen;

/*******************************************************************************
* Function Name  : TimerWKUP_Start
* Description    : Start wake up timer
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void TimerWKUP_Start(void)
{
	htk_SPI_readSingleRegister(WAKEUP_TIME_CONTROL, &DataResponse[0]);
	DataTransfer[0] = DataResponse[0] | WKUP_TSTART_NOW | WKUP_TAUTO_RELOAD;
	
	htk_SPI_writeSingleRegister(WAKEUP_TIME_CONTROL, DataTransfer[0]);
}

/*******************************************************************************
* Function Name  : TimerWKUP_Stop
* Description    : Stop wake up timer
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void TimerWKUP_Stop(void)
{
	htk_SPI_readSingleRegister(WAKEUP_TIME_CONTROL, &DataResponse[0]);
    DataTransfer[0] = DataResponse[0] | WKUP_TSTOP_NOW;
    htk_SPI_writeSingleRegister(WAKEUP_TIME_CONTROL, DataTransfer[0]);
}

/*******************************************************************************
* Function Name  : TimerWKUP_GetStatus
* Description    : Check wake up timer running status (WKUP running bit).
* Input          : None
* Output         : None
* Return         : Wake up status 
                   - WKUP_TIMER_RUNNING 
                   - WKUP_TIMER_STOP
*******************************************************************************/
uint8_t TimerWKUP_GetStatus(void)
{
    uint8_t chkStatus;

    htk_SPI_readSingleRegister(WAKEUP_TIME_CONTROL, &DataResponse[0]);
    chkStatus = DataResponse[0] & 0x20;

    /*
     * Check wake up timer is running.
     * */
    if(chkStatus == WKUP_TRUNNING)
    {
        return WKUP_TIMER_RUNNING;
    }
    else
    {
        return WKUP_TIMER_STOP;
    }
}

/*******************************************************************************
* Function Name  : TimerWKUP_SetPreScaler
* Description    : Set prescaler of wake up timer (n)
*                  for wake up period in CD mode.
*                  TWkUp_Period = ((2^n) x m)/16.38kHz
* Input          : Value of prescaler (0x00-0x0F)
* Output         : None
* Return         : Set up prescale value status
                   -  _SUCCESS_
                   -  FAILED
*******************************************************************************/
uint8_t TimerWKUP_SetPreScaler(uint8_t prescale)
{
    volatile uint8_t n_value;

    /*Mask last 4 bits of data*/
    n_value = prescale & 0x0F;

    /*Clear last 4 bits of wake up timer control register*/
    htk_SPI_readSingleRegister(WAKEUP_TIME_CONTROL, &DataResponse[0]);
    DataTransfer[0] = DataResponse[0] & ~WKUP_TIMER_PRESCALER;

    /*Write prescaler value to wake up timer control register*/
    DataTransfer[0] |= n_value;
    htk_SPI_writeSingleRegister(WAKEUP_TIME_CONTROL, DataTransfer[0]);

    /*Read again to check*/
    htk_SPI_readSingleRegister(WAKEUP_TIME_CONTROL, &DataResponse[0]);
    n_value = DataResponse[0] & WKUP_TIMER_PRESCALER;
    if(n_value == prescale)
    {
        return _SUCCESS_;
    }
    else
    {
        return FAILED;
    }
}


/*******************************************************************************
* Function Name  : TimerWKUP_SetReload
* Description    : Set timer reload of wake up timer (m)
*                  for wake up period in CD mode.
*                  TWkUp_Period = ((2^n) x m)/16.38kHz
* Input          : Value of timer reload (0x01 - 0xFF)
* Output         : None
* Return         : Set up reload value status 
                   -  _SUCCESS_
                   -  FAILED
*******************************************************************************/
uint8_t TimerWKUP_SetReload(uint8_t reload)
{
    volatile uint8_t m_value;

    /*Reload value haven't to be zero*/
    if(reload != 0)
    {
    	/*Write wake up timer reload*/
        DataTransfer[0] = reload;
        htk_SPI_writeSingleRegister(WAKEUP_TIME_RELOAD, DataTransfer[0]);

        /*Read back to check*/
        htk_SPI_readSingleRegister(WAKEUP_TIME_RELOAD, &DataResponse[0]);
        m_value = DataResponse[0];
        if(m_value == reload)
        {
            return _SUCCESS_;
        }
        else
        {
            return FAILED;
        }
    }
    else
    {
        return FAILED;
    }
}


/*******************************************************************************
* Function Name  : TimerWKUP_SetCounter
* Description    : Set up counter of wake up timer in CD mode.
                    WkUpIrq_Time = (2^count) x TWkUp_Period
                    The unit is second.
* Input          : Value of timer counter(1-15)
* Output         : None
* Return         : Set up timer counter status
                   -  _SUCCESS_
                   -  FAILED
*******************************************************************************/
uint8_t TimerWKUP_SetCounter(uint8_t counter)
{
    volatile uint8_t timer_counter;

    /*Counter value haven't to be zero*/
    if(counter != 0)
    {
    	/*Write wake up timer counter*/
        DataTransfer[0] = counter & WKUP_TIMER_COUNTER;
        htk_SPI_writeSingleRegister(WAKEUP_TIME_COUNTER, DataTransfer[0]);

        /*Read back to check*/
        htk_SPI_readSingleRegister(WAKEUP_TIME_COUNTER, &DataResponse[0]);
        timer_counter = DataResponse[0];
        timer_counter &= WKUP_TIMER_COUNTER;
        if(timer_counter == counter)
        {
            return _SUCCESS_;
        }
        else
        {
            return FAILED;
        }
    }
    else
    {
        return FAILED;
    }
}



/*******************************************************************************
* Function Name  : TimerWKUP_INIT
* Description    : Initial wake up timer before entering to CD mode.
* Input          : Wake up timer property structure.
* Output         : None
* Return         : None
*******************************************************************************/
void TimerWKUP_INIT(tBC45_WAKEUP_TIMER_PROPERTY WAKEUP_TIMER_PROPERTY)
{
    TimerWKUP_SetCounter(WAKEUP_TIMER_PROPERTY.Timer_COUNTER);
    TimerWKUP_SetPreScaler(WAKEUP_TIMER_PROPERTY.Timer_PRESCALER);
    TimerWKUP_SetReload(WAKEUP_TIMER_PROPERTY.Timer_RELOAD);
}


/*******************************************************************************
* Function Name  : BC45_CardDetection_Init
* Description    : Configuration card detection property
* Input          : tBC45_CARDDETECT_PROPERTY structure
* Output         : None
* Return         : None
*******************************************************************************/
void BC45_CardDetection_Init(tBC45_CARDDETECT_PROPERTY CD_PROPERTY)
{
    uint8_t config_property[3];
    uint8_t chk_property;
    uint8_t count;

    config_property[0] = CD_PROPERTY.CD_GOActive;
    config_property[1] = CD_PROPERTY.FD_Ignore;
    config_property[2] = CD_PROPERTY.FD_Enable;

    /*Clear check property variable*/
    chk_property = 0x00;
    for(count = 0; count < 3; count++)
    {
    	/*Set bit following CD property input*/
        switch(config_property[count])
        {
            case WKUP_CD_GoActive:
                chk_property |=  WKUP_CD_GoActive;
                break;
            case WKUP_FD_En:
                chk_property |=  WKUP_FD_En;
                break;
            case WKUP_FD_Ignore:
                chk_property |=  WKUP_FD_Ignore;
                break;
            default:
                break;
        }
    }

    /*Read wake up CD control register*/
    htk_SPI_readSingleRegister(WAKEUP_CD_CONTROL, &DataResponse[0]);
    DataTransfer[0] = DataResponse[0] & WKUP_CD_CLEAR_PROPERTY;
    /*Write CD property*/
    DataTransfer[0] |= chk_property;
    htk_SPI_writeSingleRegister(WAKEUP_CD_CONTROL, DataTransfer[0]);
}

/*******************************************************************************
* Function Name  : BC45_Mode_Selection
* Description    : Select mode of BC45 
                    - CD mode
                    - Standby mode
                    - Power Down mode
* Input          : Mode to running
* Output         : None
* Return         : Select mode status
                    - _SUCCESS_
                    - FAILED
*******************************************************************************/
uint8_t BC45_Mode_Selection(uint8_t BC45_Running_Mode)
{
    uint8_t select_mode;
    uint8_t chk_mode;
    tBC45_CARDDETECT_PROPERTY CARDDETECT_PROPERTY;

    switch(BC45_Running_Mode)
    {
        case BC45_WKUP_CD_MODE:
        /* Configure CD property */
            CARDDETECT_PROPERTY.CD_GOActive = WKUP_CD_GoActive;
            CARDDETECT_PROPERTY.FD_Enable   = ~WKUP_FD_En;
            CARDDETECT_PROPERTY.FD_Ignore   = WKUP_FD_Ignore;
            BC45_CardDetection_Init(CARDDETECT_PROPERTY);
        /* Clear all mode in BC45 system control register */
            htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
            select_mode = DataResponse[0] & BC45_CLEAR_ALL_MODE;
            DataTransfer[1] = select_mode;
            htk_SPI_writeSingleRegister(SYSTEM_CONTROL, DataTransfer[1]);
        /* Check the register is cleard all mode */
            htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
            chk_mode = DataResponse[0] & BC45_CHECK_ALL_MODE;
            if(chk_mode == 0x00)
            {
                /* Select mode */
            	select_mode = DataResponse[0] | BC45_WKUP_CD_MODE;
            	select_mode = BC45_WKUP_CD_MODE;
              DataTransfer[1] = BC45_WKUP_CD_MODE;
              htk_SPI_writeSingleRegister(SYSTEM_CONTROL, DataTransfer[1]);
              return _SUCCESS_;
            }
            else
            {
              return FAILED;
            }            
            //break;
        case BC45_IDLE_CD_MODE:
        /* Config CD property */
            CARDDETECT_PROPERTY.CD_GOActive = ~WKUP_CD_GoActive;
            CARDDETECT_PROPERTY.FD_Enable   = ~WKUP_FD_En;
            CARDDETECT_PROPERTY.FD_Ignore   = WKUP_FD_Ignore;
            BC45_CardDetection_Init(CARDDETECT_PROPERTY);
        /* Clear all mode in BC45 system control register */
            htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
            select_mode = DataResponse[0] & BC45_CLEAR_ALL_MODE;
            DataTransfer[1] = select_mode;
            htk_SPI_writeSingleRegister(SYSTEM_CONTROL, DataTransfer[1]);
        /* Check the register is cleard all mode */
            htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
            chk_mode = DataResponse[0] & BC45_CHECK_ALL_MODE;
            if(chk_mode == 0x00)
            {
                /* Select mode */
             	select_mode = DataResponse[0] | BC45_WKUP_CD_MODE;
              	select_mode = BC45_WKUP_CD_MODE;
                DataTransfer[1] = BC45_WKUP_CD_MODE;
                htk_SPI_writeSingleRegister(SYSTEM_CONTROL, DataTransfer[1]);
                return _SUCCESS_;
            }
            else
            {
                return FAILED;
            }
						//break;
        case BC45_STANDBY_MODE:
        /* Clear all mode in BC45 system control register */
        	htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
            select_mode = DataResponse[0] & BC45_CLEAR_ALL_MODE;
            DataTransfer[0] = select_mode;
            htk_SPI_writeSingleRegister(SYSTEM_CONTROL, DataTransfer[0]);
        /* Check the register is cleard all mode */
            htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
            chk_mode = DataResponse[0] & BC45_CHECK_ALL_MODE;
            if(chk_mode == 0x00)
            {
                /* Select mode */
                select_mode |= BC45_STANDBY_MODE;
                DataTransfer[0] = select_mode;
                htk_SPI_writeSingleRegister(SYSTEM_CONTROL, DataTransfer[0]);
                return _SUCCESS_;
            }
            else
            {
                return FAILED;
            }  
            //break;
        case BC45_PWR_DOWN_MODE:
        /* Clear all mode in BC45 system control register */
        	htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
            select_mode = DataResponse[0] & BC45_CLEAR_ALL_MODE;
            DataTransfer[0] = select_mode;
            htk_SPI_writeSingleRegister(SYSTEM_CONTROL, DataTransfer[0]);
        /* Check the register is cleard all mode */
            htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
            chk_mode = DataResponse[0] & BC45_CHECK_ALL_MODE;
            if(chk_mode == 0x00)
            {
                /* Select mode */
                select_mode |= BC45_PWR_DOWN_MODE;
                DataTransfer[0] = select_mode;
                htk_SPI_writeSingleRegister(SYSTEM_CONTROL, DataTransfer[0]);
                return _SUCCESS_;
            }
            else
            {
                return FAILED;
            }  
            //break;
        default:
            return FAILED;
            //break;
    }
}


/*******************************************************************************
* Function Name  : CD_ADC_Tuning
* Description    : Tuning threshold of adc I and Q
* Input          : tBC45_CD_TUNING structure
* Output         : None
* Return         : None
*******************************************************************************/
void CD_ADC_Tuning(tBC45_CD_TUNING ADC_Threshold)
{
    uint8_t Threshold_I_Low;
    uint8_t Threshold_I_High;
    uint8_t Threshold_Q_Low;
    uint8_t Threshold_Q_High;

    Threshold_I_Low = ADC_Threshold.CD_Threshold_I_L;
    Threshold_I_High = ADC_Threshold.CD_Threshold_I_H;
    Threshold_Q_Low = ADC_Threshold.CD_Threshold_Q_L;
    Threshold_Q_High = ADC_Threshold.CD_Threshold_Q_H;

    htk_SPI_writeSingleRegister(CD_THRES_I_LOW, 	Threshold_I_Low);
    htk_SPI_writeSingleRegister(CD_THRES_I_HIGH, 	Threshold_I_High);
    htk_SPI_writeSingleRegister(CD_THRES_Q_LOW, 	Threshold_Q_Low);
    htk_SPI_writeSingleRegister(CD_THRES_Q_HIGH, 	Threshold_Q_High);
}


/*******************************************************************************
* Function Name  : EnableBC45_Interrupt
* Description    : Enable Interrupt Source in BC45
* Input          : Interrupt Source
                    - CDIRQ_Mask          
                    - TimerIRQ_Mask       
                    - TxIRQ_Mask          
                    - RxIRQ_Mask          
                    - IdleIRQ_Mask        
                    - HiAlertIRQ_Mask     
                    - LoAlertIRQ_Mask     
* Output         : None
* Return         : None
*******************************************************************************/
void Interrupt_EnableBC45(uint8_t IrqEn_Source)
{
    uint8_t IrqEnable;

    IrqEnable = SetIEN_Mask | (IrqEn_Source & 0x7F);
    htk_SPI_writeSingleRegister(InterruptEN, IrqEnable);
}



/*******************************************************************************
* Function Name  : Interrupt_GetIrq_SourceBC45
* Description    : Check interrupt source from BC45
* Input          : Interrupt Source to check
* Output         : None
* Return         : Interrupt Source 
                    - CDIRQ_Mask          
                    - TimerIRQ_Mask       
                    - TxIRQ_Mask          
                    - RxIRQ_Mask          
                    - IdleIRQ_Mask        
                    - HiAlertIRQ_Mask     
                    - LoAlertIRQ_Mask 
                If not match with any IRQ source.
                    - FAILED
*******************************************************************************/
uint8_t Interrupt_GetIrq_SourceBC45(uint8_t ChkIrq_Source)
{
    uint8_t IrqSrc;

    htk_SPI_readSingleRegister(InterruptIRQ, &IrqSrc);
    IrqSrc &= 0x7F;
    IrqSrc &= ChkIrq_Source;
    switch(ChkIrq_Source)
    {
        case CDIRQ_Mask:
            if(IrqSrc == CDIRQ_Mask)
            {
                return CDIRQ_Mask;
            }
            break;
        case TimerIRQ_Mask:
            if(IrqSrc == TimerIRQ_Mask)
            {
                return TimerIRQ_Mask;
            }
            break;
        case TxIRQ_Mask:
            if(IrqSrc == TxIRQ_Mask)
            {
                return TxIRQ_Mask;
            }
            break;
        case RxIRQ_Mask:
            if(IrqSrc == RxIRQ_Mask)
            {
                return RxIRQ_Mask;
            }
            break;
        case IdleIRQ_Mask:
            if(IrqSrc == IdleIRQ_Mask)
            {
                return IdleIRQ_Mask;
            }
            break;
        case HiAlertIRQ_Mask:
            if(IrqSrc == HiAlertIRQ_Mask)
            {
                return HiAlertIRQ_Mask;
            }
            break;
        case LoAlertIRQ_Mask:
            if(IrqSrc == LoAlertIRQ_Mask)
            {
                return LoAlertIRQ_Mask;
            }
            break;
        default:
            return FAILED;
						//break;
    }

    return FAILED;
}

/*******************************************************************************
* Function Name  : BC45_CDMode_Exit
* Description    : Exit from CD mode
* Input          : None
* Output         : None
* Return         : Select mode status
                    - _SUCCESS_
                    - FAILED
*******************************************************************************/
uint8_t BC45_CDMode_Exit(void)
{
    uint8_t select_mode;
    uint8_t chk_mode;

    TimerWKUP_Stop();

    /* Clear all mode in BC45 system control register */
    htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
    select_mode = DataResponse[0] & BC45_CLEAR_ALL_MODE;
    DataTransfer[1] = select_mode;
    htk_SPI_writeSingleRegister(SYSTEM_CONTROL, DataTransfer[1]);
    /* Check the register is cleard all mode */
    htk_SPI_readSingleRegister(SYSTEM_CONTROL, &DataResponse[0]);
    chk_mode = DataResponse[0] & BC45_CHECK_ALL_MODE;
    if(chk_mode == 0x00)
    {
        return _SUCCESS_;
    }
    else
    {
        return FAILED;
    } 
} 

/*******************************************************************************
* Function Name  : ADC calibration function
* Description    : Calibrate ADC of BC45 before using
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ADC_Calibration(void)
{
    uint8_t irq_src = 0;
    uint8_t cmd;

    /*Write adc calibration command to register 0x01*/
    cmd = ADC_CAL_CMD;
	  do {
    htk_SPI_writeSingleRegister(CMDPAGE, cmd);
	  htk_SPI_readSingleRegister(CMDPAGE, &cmd);
		}while((cmd & ADC_CAL_CMD)!=ADC_CAL_CMD);
		
    /*Waiting for idle irq is set*/
    while(irq_src != IdleIRQ_Mask)
    {
    	htk_SPI_readSingleRegister(InterruptIRQ, &irq_src);
    	irq_src = irq_src & IdleIRQ_Mask;
    }

    /*Disable and Clear all irq*/
    BC45_Disable_And_ClearFlag_IRQ( ALL_IRQ_SOURCE | CDIRQ_Mask );
}



