
/**
 ******************************************************************************
 *
 * @file        MG32x02z_ScanKey_API.c
 * @brief       Scan user press key by ADC. 
 *
 * @par         Project
 *              MG32x02z
 * @version     V1.02
 * @date        2022/09/28
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 *
 ******************************************************************************* 
 * @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */


/* External control parameters variables -------------------------------------*/

/* Includes ------------------------------------------------------------------*/
#include "MG32x02z_ScanKey_API.h"
#include "MG32x02z_DACOutput_API.h"
#include "MG32x02z_Microphone_API.h"
#include "RingBuffer.h"
#include "UserEvent.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef   mADC;
TM_HandleTypeDef    mTM20;
//uint16_t            KeyMatrix;
//uint16_t            ADCDatArray[5];

/* Private function prototypes -----------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/
extern DAC_HandleTypeDef    mDAC;

/* Private define ------------------------------------------------------------*/

/**
 *******************************************************************************
 * @brief       Initial ADC with ADC_OneShot mode 
 * @param[in]   None
 * @return      None
 *******************************************************************************
 */
void API_ADC_Init(void)
{
    // make sure :
    //===Set CSC init====
    //MG32x02z_CSC_Init.h(Configuration Wizard)
    //Select CK_HS source = CK_IHRCO
    //Select IHRCO = 12M
    //  Select CK_PLLI Divider = CK_HS/2
    //  Select CK_PLL Multiplication factor = CK_PLLIx16
    //  Select CK_PLLO Divider = CK_PLL/4
    //Select CK_MAIN Source = CK_PLLO
    //Configure PLL->Select APB Prescaler = CK_MAIN/1
    //Configure Peripheral On Mode Clock->ADC = Enable
    //Configure Peripheral On Mode Clock->Port A = Enable

    //==Set GPIO init 
    //MG32x02z_GPIO_Init.h(Configuration Wizard)->Use GPIOA->PA3,PA14,PA15
    //GPIO port initial is 0xFFFF
    //PA3,PA14,PA15 mode is AIO
    //PA3,PA14,PA15 function GPA3,14,15
    
    // Config ADC in ADC_ONESHOT mode.

    // ------------------------------------------------------------------------
    // 1.Config ADC base parameter.
    // ------------------------------------------------------------------------
    mADC.Instance                   = ADC0;                     // for ADC0
    mADC.Init.ADCConType            = ADC_CONV_SINGLE;          // Single-end type
    mADC.Init.ADCClock              = ADC_CLOCKPROC_DIV2;       // ADC_Clock = ADCK/2 (MG32F02A128 ~1000k@24Clks)
    mADC.Init.Resolution            = ADC_RESOLUTION_12B;       // ADC conversion resolution
    mADC.Init.DataAlign             = ADC_DATAALIGN_RIGHT;      // ADC data is Right-justified
    mADC.Init.ConversionMode        = ADC_ONESHOT;              // ADC_ONESHOT to converion 
    mADC.Init.LowPowerAutoWait      = ADC_CONTINUE_NEXT;        // ADC will replace the older conversion data (WAIT_EN for scan/loop mode)
    mADC.Init.LowPowerAutoPowerOff  = ADC_NORMAL_POWER;         // ADC keep in normal Power level
    mADC.Init.TriggerConverionSrc   = ADC_SOFTWARE_START;       // ADC software trigger to convert
    mADC.Init.TriggerConverionEdge  = ADC_TRIGCONVEDGE_NONE;    // ADC convert signal from external trigger event edge select
    mADC.Init.Overrun               = ADC_ACCEPT_OVERRUN;       // It will overrun the conversion data   
    mADC.Init.ExtendSamplingTime    = 0;                        // Extend time of 'Sample & Hold' of ADC conversion state (0 ADC_Clock)
    MID_ADC_Init(&mADC);
}


static uint8_t gSerialKeyPop = 1;
/**
 *******************************************************************************
 * @brief       Sample serial key matrix and decode it.
 * @param[in]   None
 * @return      None
 *******************************************************************************
 */
uint16_t API_ADC_GetSerialKey(void)
{
    ADC_ChannelConfTypeDef ADCChannelMux;
    uint16_t    ADCData;

    // select Serial Key channel of ADC
    ADCChannelMux.Channel = ADC_CHANNEL_15;
    MID_ADC_ConfigChannel(&mADC, &ADCChannelMux);
    
    // Trigger ADC Conversion
    MID_ADC_Start(&mADC);
    //  poll ADC flag
    MID_ADC_PollForConversion(&mADC, 10);
    
    
    // ------------------------------------------------------------------------
    // determination serial Key0~Key8
    // ------------------------------------------------------------------------
    ADCData = (uint16_t)MID_ADC_GetValue(&mADC);
    
    // Bisection method
    if(ADCData < SKey4_LV)
    {
        // Bisection method
        if (ADCData < SKey2_LV) 
        {
            if ((ADCData < 100) && (gSerialKeyPop != 0))
            {
                gSerialKeyPop = 0;
                RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY0_Push);
                gIdleCount = MID_GetTick(); // Reload Tick Counter
                return Key0;                // press Key0
            }
            else if(gSerialKeyPop != 0)
            {
                gSerialKeyPop = 0;
                RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY1_Push);
                gIdleCount = MID_GetTick(); // Reload Tick Counter
                return Key1;                // press Key1
            }
        }
        else
        {
            if ((ADCData < SKey3_LV) && (gSerialKeyPop != 0))
            {
                gSerialKeyPop = 0;
                RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY2_Push);
                gIdleCount = MID_GetTick(); // Reload Tick Counter
                return Key2;                // press Key2
            }
            else if(gSerialKeyPop != 0)
            {
                gSerialKeyPop = 0;
                RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY3_Push);
                gIdleCount = MID_GetTick(); // Reload Tick Counter
                return Key3;                // press Key3
            }
        }
    }
    else if(ADCData < SKey8_HV)
    {
        // Bisection method
        if (ADCData < SKey7_LV)
        {
            if ((ADCData < SKey4_HV) && (gSerialKeyPop != 0))
            {
                gSerialKeyPop = 0;
                RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY4_Push);
                gIdleCount = MID_GetTick(); // Reload Tick Counter
                return Key4;                // press Key4
            }
            else if ((ADCData < SKey5_HV) && (gSerialKeyPop != 0))
            {
                gSerialKeyPop = 0;
                RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY5_Push);
                gIdleCount = MID_GetTick(); // Reload Tick Counter
                return Key5;                // press Key5
            }
            else if(gSerialKeyPop != 0)
            {
                gSerialKeyPop = 0;
                RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY6_Push);
                gIdleCount = MID_GetTick(); // Reload Tick Counter
                return Key6;                // press Key6
            }
        }
        else if(ADCData < SKey7_HV)
        {
            gSerialKeyPop = 0;
            RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY7_Push);
            gIdleCount = MID_GetTick(); // Reload Tick Counter
            return Key7;                    // press Key7
        }
        else if((ADCData < SKey8_HV) && (gSerialKeyPop != 0))
        {
            gSerialKeyPop = 0;
            RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY8_Push);
            gIdleCount = MID_GetTick(); // Reload Tick Counter
            return Key8;                    // press Key8
        }
        else
        {
            if(gSerialKeyPop == 0)
            {
                gSerialKeyPop = 1;
                RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY_Pop);
                gIdleCount = MID_GetTick(); // Reload Tick Counter
                return NoPressKey;                  // No press any serial key
            }
        }
    }
    else
    {
        if(gSerialKeyPop == 0)
        {
            gSerialKeyPop = 1;
            RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY_Pop);
            gIdleCount = MID_GetTick(); // Reload Tick Counter
            return NoPressKey;                  // No press any serial key
        }
    }
    return NoPressKey;
}

static uint8_t gParalleKeyPop = 0;
/**
 *******************************************************************************
 * @brief       Sample perallel key matrix and decode it.
 * @param[in]   None
 * @return      None
 *******************************************************************************
 */
uint16_t API_ADC_GetParallelKey(void)
{
    ADC_ChannelConfTypeDef ADCChannelMux;
    uint16_t    ADCData;
    
    // select Parallel Key channel of ADC
    ADCChannelMux.Channel = ADC_CHANNEL_14;
    MID_ADC_ConfigChannel(&mADC, &ADCChannelMux);
    
    // Trigger ADC Conversion
    MID_ADC_Start(&mADC);
    //  poll ADC flag
    MID_ADC_PollForConversion(&mADC, 10);
    
    // ------------------------------------------------------------------------
    // determination parallel Key10~Key12
    // ------------------------------------------------------------------------
    ADCData = (uint16_t)MID_ADC_GetValue(&mADC);
    
    if (ADCData < PKey0_HV)
    {
        gParalleKeyPop = 0;
        RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY10_Push);
        gIdleCount = MID_GetTick(); // Reload Tick Counter
        return Key10;                   // press Key10
    }
    else if (ADCData < PKey1_HV)
    {
        gParalleKeyPop = 0;
        RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY11_Push);
        gIdleCount = MID_GetTick(); // Reload Tick Counter
        return Key11;                   // press Key11
    }
    else if (ADCData < PKey2_HV)
    {
        gParalleKeyPop = 0;
        RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY12_Push);
        gIdleCount = MID_GetTick(); // Reload Tick Counter
        return Key12;                   // press Key12
    }
    else
    {
        if(gParalleKeyPop == 0)
        {
            gParalleKeyPop = 1;
            RingBufferU8_WriteByte(&gEventQueue, ADCKEY_KEY_Pop);
            gIdleCount = MID_GetTick(); // Reload Tick Counter
            return NoPressKey;              // No press any perallel key
        }
    }
    return NoPressKey;
}


