/*
  ******************************************************************************
  * @file    app.c
  * @author  Xiao Han
  * @version V1.0.0
  * @date    2021
  * @brief   ADC demo source code.
  ******************************************************************************
*/
 
#include  "app.h"
#include  "bsp_adc.h"
#include  "temp_sensor.h"

#define BUFFER_LENGTH    (21)

uint32_t gu32_AdcBuffer[BUFFER_LENGTH];

GPIO_InitTypeDef KEY_Handle;
#define USERKEY_PORT	GPIOB
#define USERKEY_PIN		GPIO_PIN_9

extern __IO uint32_t u32_GroupFlag;
extern __IO uint32_t u32_AwdFlag;
extern uint32_t      *AdcResults;            /* ADC global results handle */

#define TIM_CLOCK_FREQ            (10000)  
TIM_Base_InitTypeDef TIM_TimeBaseStructure;    

/*********************************************************************************
* Function    : UserKEY_Init
* Description : User key initialize
* Input       : 
* Output      : 
**********************************************************************************/
void UserKEY_Init(void)
{
    KEY_Handle.Pin       = USERKEY_PIN;
    KEY_Handle.Mode      = GPIO_MODE_INPUT;
    KEY_Handle.Pull      = GPIO_PULLUP;
    KEY_Handle.Alternate = GPIO_FUNCTION_0;

    GPIO_Init(USERKEY_PORT, &KEY_Handle);
}

/*********************************************************************************
* Function    : UserKEY_Get
* Description : detection button is pressed
* Input       : 
* Output      : 
**********************************************************************************/
bool UserKEY_Get(void)
{
    if (Bit_RESET == GPIO_ReadInputDataBit(USERKEY_PORT, USERKEY_PIN)) 
    {
        System_Delay_MS(20);
        
        if (Bit_RESET == GPIO_ReadInputDataBit(USERKEY_PORT, USERKEY_PIN)) 
        {
            return true;
        }
    }

    return false;
}

/************************************************************************
 * function   : ADC_Init_Dma_Diff_Nchannels
 * Description: This is a adc polling demo, 
 *              for 16 single-ended channels adc convert application
 ************************************************************************/ 
void ADC_Test_Polling_Nchannels(void)
{
    uint32_t i, VrefP, Voltage;
    
    uint32_t lu32_COM_OK  = 0;

    printfS("The ADC test ADC_Test_Polling_Nchannels start.");

    VrefP = ADC_GetVrefP();
    
    printfS("The VrefP value is : %d \r\n", VrefP);
    
    UserKEY_Init();
    
    printfS("---------- Please press the USR_PB button ----------\r\n");

    ADC_Init_Polling_Nchannels();

    while(1)
    {
        while(false == UserKEY_Get());
        System_Delay_MS(500);
        
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            gu32_AdcBuffer[i] = 0;
        }
        
        ADC_Polling(gu32_AdcBuffer, 16, 0);
        
        for (i = 0; i < 16; i++)
        {
            printfS("The adc convert result : Channel %d = 0x%08x. ", gu32_AdcBuffer[i]>>16 & 0xFF,gu32_AdcBuffer[i]);
            Voltage = (gu32_AdcBuffer[i]&0xFFF)*VrefP/4095;
            printfS("The Voltage is: %d mV \r\n", Voltage);
            
            lu32_COM_OK++;
        }
        
        printfS("ADC Test OK count %d times \r\n",  lu32_COM_OK);
    }
}

/************************************************************************
 * function   : ADC_Test_Dma_Diff_Nchannels
 * Description: This is a adc dma demo, 
 *              for 8 Diff channels adc convert application
 ************************************************************************/ 
void ADC_Test_Dma_Diff_Nchannels(void)
{
    uint32_t i, VrefP;
    int32_t Voltage;
    int16_t OutData;
    
    uint32_t lu32_COM_OK  = 0;

    printfS("The ADC test ADC_Test_Dma_Diff_Nchannels start.");

    VrefP = ADC_GetVrefP();
    
    printfS("The VrefP value is : %d \r\n", VrefP);
    
    UserKEY_Init();
    
    printfS("---------- Please press the USR_PB button ----------\r\n");
    
    ADC_Init_Dma_Diff_Nchannels();
    
    for (i = 0; i < BUFFER_LENGTH; i++)
    {
        gu32_AdcBuffer[i] = 0;
    }
    
    ADC_DMA_Convert(gu32_AdcBuffer, 8);
    
    while(1)
    {
        while(false == UserKEY_Get());
        System_Delay_MS(500);
        
		for (i = 0; i < 8; i++)
		{
			printfS("The adc convert result : Channel %d = 0x%08x. ", gu32_AdcBuffer[i]>>16 & 0xFF,gu32_AdcBuffer[i]);

			OutData = (int16_t)gu32_AdcBuffer[i];
			Voltage = OutData*(int32_t)VrefP/2047;
			printfS("The Voltage is: %d mV \r\n", Voltage);
			
			lu32_COM_OK++;
		}
		
		printfS("ADC Test OK count %d times \r\n",  lu32_COM_OK);
    }
}

/************************************************************************
 * function   : ADC_Test_Dma_Single_Nchannels
 * Description: This is a adc dma demo, 
 *              for 16 single-ended channels adc convert application
 ************************************************************************/ 
void ADC_Test_Dma_Single_Nchannels(void)
{
    uint32_t i, VrefP, Voltage;
    
    uint32_t lu32_COM_OK  = 0;

    printfS("The ADC test ADC_Test_Dma_Single_Nchannels start.");

    VrefP = ADC_GetVrefP();
    
    printfS("The VrefP value is : %d \r\n", VrefP);

    UserKEY_Init();
    
    printfS("---------- Please press the USR_PB button ----------\r\n");
    
    ADC_Init_Dma_Single_Nchannels();

    for (i = 0; i < BUFFER_LENGTH; i++)
    {
        gu32_AdcBuffer[i] = 0;
    }
    
    ADC_DMA_Convert(gu32_AdcBuffer, 16);
    
    while(1)
    {
        while(false == UserKEY_Get());
        System_Delay_MS(500);
        
        for (i = 0; i < 16; i++)
        {
            printfS("The adc convert result : Channel %d = 0x%08x. ", gu32_AdcBuffer[i]>>16 & 0xFF,gu32_AdcBuffer[i]);
            Voltage = (gu32_AdcBuffer[i]&0xFFF)*VrefP/4095;
            printfS("The Voltage is: %d mV \r\n", Voltage);
            
            lu32_COM_OK++;
        }
        
        printfS("ADC Test OK count %d times \r\n",  lu32_COM_OK);    
    }
}

/*********************************************************************************************
 * function   : ADC_Test_IT_Injected_WatchDog
 * Description: This is a adc interrupt demo, 
 *              for 15 single-ended regular channels and 1 injected channel
 *              convert application.
 *              Press down the USR_PB button until the Injected event occur.
 *              If the Injected channel level out of window,the watchdog event will occur.
 *********************************************************************************************/ 
void ADC_Test_IT_Injected_WatchDog(void)
{
    uint32_t i, VrefP, Voltage;
    
    uint32_t lu32_COM_OK  = 0;

    printfS("The ADC test ADC_Test_IT_Injected_WatchDog start.");

    VrefP = ADC_GetVrefP();
    
    printfS("The VrefP value is : %d \r\n", VrefP);
    
    UserKEY_Init();
    
    printfS("---------- Please press down the USR_PB button until the Injected event occur ----------\r\n");

    ADC_Init_IT_Injected_WatchDog();

    AdcResults = gu32_AdcBuffer;  
    
    u32_GroupFlag = 0;
    u32_AwdFlag = 0;
    
    for (i = 0; i < BUFFER_LENGTH; i++)
    {
        gu32_AdcBuffer[i] = 0;
    }
    
    ADC_Cmd(ADC, ENABLE);

    ADC_SoftwareStartConvCmd(ADC, ENABLE);

    while(1)
    {
        if(true == UserKEY_Get())
        {
            ADC_SoftwareStartInjectedConvCmd(ADC, ENABLE);
        }
                
        while(u32_GroupFlag == 0);
        
        u32_GroupFlag = 0;
        
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            if(gu32_AdcBuffer[i] & BSP_ADC_EOC_FLAG)
            {
                printfS("Regular Channel %d = 0x%08x. ", gu32_AdcBuffer[i]>>16 & 0xFF,gu32_AdcBuffer[i]);
                Voltage = (gu32_AdcBuffer[i]&0xFFF)*VrefP/4095;
                printfS("The Voltage is: %d mV \r\n", Voltage);
            }
            else if(gu32_AdcBuffer[i] & BSP_ADC_JEOC_FLAG)
            {
                if(u32_AwdFlag)
                {
                    printfS("Injected Channel Level Out Of Window. \r\n");
                    u32_AwdFlag = 0;
                }
                printfS("Injected Channel %d = 0x%08x. ", gu32_AdcBuffer[i]>>16 & 0xFF,gu32_AdcBuffer[i]);
                Voltage = (gu32_AdcBuffer[i]&0xFFF)*VrefP/4095;
                printfS("The Voltage is: %d mV \r\n", Voltage);
            }
            
            lu32_COM_OK++;
        }
        
        printfS("ADC Test OK count %d times \r\n",  lu32_COM_OK);
        
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            gu32_AdcBuffer[i] = 0;
        }

        System_Delay_MS(2000);
    }
}

/*********************************************************************************
* Function    : ADC_TIM6_Init
* Description :	Init the TIM6 for ADC Trigger .
* Input       : 
* Output      : 
**********************************************************************************/
static void ADC_TIM6_Init(void)
{
    uint32_t timer_clock; 
    
    timer_clock = System_Get_APBClock(); 
    
    if (System_Get_SystemClock() != System_Get_APBClock())  // if hclk/pclk != 1, then timer clk = pclk * 2  
    {
       timer_clock =  System_Get_APBClock() << 1;    
    }
    
	TIM_TimeBaseStructure.ClockDivision = TIM_CLOCKDIVISION_DIV1; 
	TIM_TimeBaseStructure.CounterMode = TIM_COUNTERMODE_UP; 
	TIM_TimeBaseStructure.RepetitionCounter = 0;  
	TIM_TimeBaseStructure.Prescaler = (timer_clock/TIM_CLOCK_FREQ) - 1;  
	TIM_TimeBaseStructure.Period = (TIM_CLOCK_FREQ/1000)*2000 - 1;  // 2000ms 
	    
	TIM_TimeBase_Init(TIM6, &TIM_TimeBaseStructure);           

    /* Selects the TIMx Trigger Output Mode */
    TIM_SelectOutputTrigger(TIM6, TIM_TRGO_UPDATE);

    /* TIM6 enable counter */
    TIM_Cmd(TIM6, ENABLE);
}


/*********************************************************************************************
 * function   : ADC_Test_IT_Injected_TimTrig
 * Description: This is a adc interrupt demo, 
 *              for 15 single-ended regular channels and 1 injected channel
 *              convert application.
 *              TIM6 trig the Injected event every 2 seconds.
 *********************************************************************************************/ 
void ADC_Test_IT_Injected_TimTrig(void)
{
    uint32_t i, VrefP, Voltage;
    
    uint32_t lu32_COM_OK  = 0;

    printfS("The ADC test ADC_Test_IT_Injected_TimTrig start.");

    VrefP = ADC_GetVrefP();
    
    printfS("The VrefP value is : %d \r\n", VrefP);
    
    printfS("---------- TIM6 trig the Injected event every 2 seconds ----------\r\n");

    AdcResults = gu32_AdcBuffer;
    
    ADC_Init_IT_Injected_TimTrig();
    ADC_TIM6_Init();

    u32_GroupFlag = 0;
    
    for (i = 0; i < BUFFER_LENGTH; i++)
    {
        gu32_AdcBuffer[i] = 0;
    }
    
    ADC_Cmd(ADC, ENABLE);

    ADC_SoftwareStartConvCmd(ADC, ENABLE);

    while(1)
    {                
        while(u32_GroupFlag == 0);
        
        u32_GroupFlag = 0;
        
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            if(gu32_AdcBuffer[i] & BSP_ADC_EOC_FLAG)
            {
                printfS("Regular Channel %d = 0x%08x. ", gu32_AdcBuffer[i]>>16 & 0xFF,gu32_AdcBuffer[i]);
                Voltage = (gu32_AdcBuffer[i]&0xFFF)*VrefP/4095;
                printfS("The Voltage is: %d mV \r\n", Voltage);
            }
            else if(gu32_AdcBuffer[i] & BSP_ADC_JEOC_FLAG)
            {
                printfS("Injected Channel %d = 0x%08x. ", gu32_AdcBuffer[i]>>16 & 0xFF,gu32_AdcBuffer[i]);
                Voltage = (gu32_AdcBuffer[i]&0xFFF)*VrefP/4095;
                printfS("The Voltage is: %d mV \r\n", Voltage);
            }
            
            lu32_COM_OK++;
        }
        
        printfS("ADC Test OK count %d times \r\n",  lu32_COM_OK);
        
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            gu32_AdcBuffer[i] = 0;
        }

        System_Delay_MS(1000);
    }
}

/************************************************************************
 * function   : ADC_Test
 * Description: The adc demo. 
 * input : mode: The test mode.
 * return: none
 ************************************************************************/
void ADC_Test(enum_TEST_mode mode)
{
    printfS("ADC Test is Ready!!! \r\n");
        
    switch(mode)
    {
        case TEST_POLLING_NCHANNELS:
            ADC_Test_Polling_Nchannels();
            break;
        case TEST_DMA_DIFF_NCHANNELS:
            ADC_Test_Dma_Diff_Nchannels();
            break;
        case TEST_DMA_SINGLE_NCHANNELS:
            ADC_Test_Dma_Single_Nchannels();
            break;
        case TEST_IT_INJECTED_TIMTRIG:
            ADC_Test_IT_Injected_TimTrig();
            break;
        case TEST_IT_INJECTED_WATCHDOG:
            ADC_Test_IT_Injected_WatchDog();
            break;
        case TEST_TEMPERATURE_SENSOR:
            ADC_TemperatureSensor_Test();
            break;
        default:
            break;
    }

    printfS("ADC Test End!!! \r\n");
}
