


/**
 ******************************************************************************
 *
 * @file        KEYBOARD.c
 * @brief       The KEYBOARD Code's c file.
 *
 * @par         Project
 *              MG32
 * @version     V1.05
 * @date        2026/01/22
 * @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.
 *******************************************************************************
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "MG32_USBD_Keyboard_API.h"
#include "MG32_RGB_API.h"
#include "MG32_RGB_API.h"
#include "MG32_USBD_API.h"
#include "MG32_TM_DRV.h"
#include "MG32_URT_DRV.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define KB_ROW      EXIC_PC
#define KB_ROW1     EXIC_PB

#define KB_ROW_IT   EXIC_PC_IT
#define KB_ROW1_IT  EXIC_PB_IT

#define KB_DELAY_TM URT2

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
KEYBOARD_TypeDef    KB;                       // Keyboard relationship software control parameter.

/* Private function prototypes -----------------------------------------------*/
void EXINT2_IRQHandler(void);
void EXINT1_IRQHandler(void);

static void API_KB_LED_OFF(void);
static uint32_t API_KB_Scaning( uint8_t Scan_Index);
static void API_KB_ScanKeyStatus(void);
static FlagStatus API_KB_CheckColumnGhostKey( uint8_t CKGhost_Column);
static void API_KB_Keyboard_Function(void);
static void API_KB_TranslateToKeyCode(void);
static void API_KB_TranslateToKeyCode_Flow(void);
static void API_KB_Transfer_STDModifyCode(void);
static void API_KB_TransferMultiMediaCode(void);
static void API_KB_TransferSTDNormalCode(void);
static void API_KB_CheckUpdate(void);
static void API_KB_UpdateMultiMediaKey(void);
static void API_KB_UpdateStandardKey(void);
static void API_KB_CheckScanIn(void);
static void API_KB_CheckScanInMatrix(void);
static void API_KB_CheckUpdateKeyMatrix(void);
static void API_KB_CheckGhostKey(void);

/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/


/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
uint16_t const KeyScan1_Table[(KB_SCAN_COLUMN + 1)][KB_SCAN_USB_PORT] = {
                                                                          {0x3E80,0x0001,0xF000}, {0x5E80,0x0001,0xF000}, {0x6E80,0x0001,0xF000}, {0x7C80,0x0001,0xF000}, 
                                                                          {0x7A80,0x0001,0xF000}, {0x7680,0x0001,0xF000}, {0x7E80,0x0000,0xF000}, {0x7E00,0x0001,0xF000},
                                                                          {0x7E80,0x0001,0xE000}, {0x7E80,0x0001,0xD000}, {0x7E80,0x0001,0xB000}, {0x7E80,0x0001,0x7000},
                                                                          {0x0000,0x0000,0x0000}, 
                                                                        };

uint16_t const KeyScan0_Table[(KB_SCAN_COLUMN + 1)][KB_SCAN_USB_PORT] = {
                                                                          {0x4000,0x0000,0x0000}, {0x2000,0x0000,0x0000}, {0x1000,0x0000,0x0000}, {0x0200,0x0000,0x0000}, 
                                                                          {0x0400,0x0000,0x0000}, {0x0800,0x0000,0x0000}, {0x0000,0x0001,0x0000}, {0x0080,0x0000,0x0000}, 
                                                                          {0x0000,0x0000,0x1000}, {0x0000,0x0000,0x2000}, {0x0000,0x0000,0x4000}, {0x8000,0x0000,0x0000}, 
                                                                          {0x7E80,0x0001,0xF000}, 
                                                                        };
                                                               
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   No
 * @note        Keyboard / Keypad Page Table (standard)


{     0 =      Reserved,    1  = ErrRollOver,   2 =       POSTFail,   3  = ErrUndefined,    4 =              A,    5 =           B,    6 =               C,    7 =           D,    }
{     8 =             E,    9  =           F,  10 =              G,  11  =            H,   12 =              I,   13 =           J,   14 =               K,   15 =           L,    }
{    16 =             M,   17  =           N,  18 =              O,  19  =            P,   20 =              Q,   21 =           R,   22 =               S,   23 =           T,    }
{    24 =             U,   25  =           V,  26 =              W,  27  =            X,   28 =              Y,   29 =           Z,   30 =           1 / !,   31 =       2 / @,    }
{    32 =         3 / #,   33  =       4 / $,  34 =          5 / %,  35  =        6 / ^,   36 =          7 / &,   37 =       8 / *,   38 =           9 / (,   39 =       0 / ),    }
{    40 = Return(Enter),   41  =      ESCAPE,  42 =      Backspace,  43  =          Tab,   44 =       Spacebar,   45 =       - / _,   46 =           = / +,   47 =       [ / {,    }
{    48 =         ] / },   49  =       \ / |,  50 =               ,  51  =        ; / :,   52 =          ' / ",   53 =       ` / ~,   54 =           , / <,   55 =       . / >,    }
{    56 =         / / ?,   57  =   Caps Lock,  58 =             F1,  59  =           F2,   60 =             F3,   61 =          F4,   62 =              F5,   63 =          F6,    }
{    64 =            F7,   65  =          F8,  66 =             F9,  67  =          F10,   68 =            F11,   69 =         F12,   70 =     PrintScreen,   71 = Scroll Lock,    }
{    72 =         Pause,   73  =      Insert,  74 =           Home,  75  =       PageUp,   76 =         Delete,   77 =         End,   78 =        PageDown,   79 =  RightArrow,    }
{    80 =     LeftArrow,   81  =   DownArrow,  82 =        UpArrow,  83  =     Num Lock,   84 =              /,   85 =           *,   86 =               -,   87 =           +,    }
{    88 =         Enter,   89  =     1 / End,  90 = 2 / Down Arrow,  91  =   3 / PageDn,   92 = 4 / Left Arrow,   93 =           5,   94 = 6 / Right Arrow,   95 =  7 and Home,    }
{    96 =  8 / Up Arrow,   97  =  9 / PageUp,  98 =     0 / Insert,  99  =   . / Delete,  100 =  Non-US \ / | ,  101 = Application,  224 =     LeftControl,  225 =   Leftshift,    }
{   226 =       LeftAlt,  227  =    Left GUI, 228 =   RightControl, 229  =   RightShift,  230 =       RightAlt,  231 =   Right GUI,                                                }  


 *******************************************************************************
 */ 
#if MG32_USBD_KEYBOARD_RGB_EN != API_RGB_DISABLE

const uint8_t Default_KeyCode_Table[KB_TOTAL_KEY]= 			
{
//Column        0          1        2              3        4                  5                   6                7    8    9   10   11    // Row
               58,        30,      20,             4,       0,               227,                 69,              46,  48,   0,   0, 101,   // 2
               59,        31,      26,            22,      29,               226,                  0,              42,  49,  40, 229, 228,   // 3
               60,        32,       8,             7,      27,                 0,                 70,              73,  76,   0,   0,  80,   // 4
               61,        33,      21,             9,       6,                 0,                 71,              74,  77,   0,  82,  81,   // 5
        KB_VOL_UP, KB_VOL_DN, KB_MUTE, KB_NEXT_TRACK, KB_PLAY, KB_PREVIOUS_TRACK,                 67,              39,  19,  51,  55, 231,   // 0
               41,        53,      43,            57,     225,               224,                 68,              45,  47,  52,  56,   0,   // 1
                0,         0,       0,             0,       0,                 0,                  0,               0,   0,   0,   0,   0,   // 11  
               62,        34,      23,            10,      25,                44,                 72,              75,  78,   0,   0,  79,   // 6
               63,        35,      28,            11,       5,                 0, API_RGB_KB_SUBMODE, API_RGB_KB_MODE,  83,  95,  92,  89,   // 7	
               64,        36,      24,            13,      17,                 0,   API_RGB_KB_COLOR,              84,  96,  93,  90,  98,   // 8
               65,        37,      12,            14,      16,                 0,                  0,              85,  97,  94,  91,  99,   // 9
               66,        38,      18,            15,      54,               230,                  0,              86,  87,   0,  88,   0,   // 10
};
#else

const uint8_t Default_KeyCode_Table[KB_TOTAL_KEY]= 			
{
//Column        0          1        2              3        4                  5                   6                7    8    9   10   11    // Row
               58,        30,      20,             4,       0,               227,                 69,              46,  48,   0,   0, 101,   // 2
               59,        31,      26,            22,      29,               226,                  0,              42,  49,  40, 229, 228,   // 3
               60,        32,       8,             7,      27,                 0,                 70,              73,  76,   0,   0,  80,   // 4
               61,        33,      21,             9,       6,                 0,                 71,              74,  77,   0,  82,  81,   // 5
        KB_VOL_UP, KB_VOL_DN, KB_MUTE, KB_NEXT_TRACK, KB_PLAY, KB_PREVIOUS_TRACK,                 67,              39,  19,  51,  55, 231,   // 0
               41,        53,      43,            57,     225,               224,                 68,              45,  47,  52,  56,   0,   // 1
                0,         0,       0,             0,       0,                 0,                  0,               0,   0,   0,   0,   0,   // 11  
               62,        34,      23,            10,      25,                44,                 72,              75,  78,   0,   0,  79,   // 6
               63,        35,      28,            11,       5,                 0,                  0,               0,  83,  95,  92,  89,   // 7	
               64,        36,      24,            13,      17,                 0,                  0,              84,  96,  93,  90,  98,   // 8
               65,        37,      12,            14,      16,                 0,                  0,              85,  97,  94,  91,  99,   // 9
               66,        38,      18,            15,      54,               230,                  0,              86,  87,   0,  88,   0,   // 10
};



#endif
/**
 *******************************************************************************
 * @brief	    Keyboard wakeup interrupt Handler.
 * @details     
 * @exception   No
 * @note              
 *******************************************************************************
 */
void EXINT2_IRQHandler(void)
{

    EXIC_ClearPxTriggerEventFlag( KB_ROW, (EXIC_PX_PIN0 | EXIC_PX_PIN1 | EXIC_PX_PIN2 | EXIC_PX_PIN3 | EXIC_PX_PIN7 | \
                                           EXIC_PX_PIN8 | EXIC_PX_PIN9 | EXIC_PX_PIN10 | EXIC_PX_PIN11));
    

    Ep0.USBStatus = Ep0.USBStatus | USB_STATUS_BUS_EXTIEVENT_WAKEUP;
}

/**
 *******************************************************************************
 * @brief	    Keyboard wakeup interrupt Handler for ROW1.
 * @details     
 * @exception   No
 * @note              
 *******************************************************************************
 */
void EXINT1_IRQHandler(void)
{
    EXIC_ClearPxTriggerEventFlag(KB_ROW1,(EXIC_PX_PIN14 | EXIC_PX_PIN15));
    

    Ep0.USBStatus = Ep0.USBStatus | USB_STATUS_BUS_EXTIEVENT_WAKEUP;
}

/**
 *******************************************************************************
 * @brief	    KEYBOARD control initial.
 * @details     
 * @return      
 * @exception   No
 * @note        Delay from 5us to 1.5ms ( in CK_APB = 48MHz)
 *******************************************************************************
 */
void KB_Delay(uint16_t KB_DELAY_TIME)
{
    URT_TriggerTimeoutTimerRst_SW( KB_DELAY_TM);
    URT_ClearITFlag( KB_DELAY_TM , URT_IT_TMO);
    URT_SetTimeoutTimerCompare( KB_DELAY_TM , KB_DELAY_TIME);
    URT_TimeroutTimer_Cmd( KB_DELAY_TM , ENABLE);
    while( URT_GetITSingleFlagStatus( KB_DELAY_TM , URT_IT_TMO) == DRV_UnHappened);
    URT_TimeroutTimer_Cmd( KB_DELAY_TM , DISABLE);
    
    
}
/**
 *******************************************************************************
 * @brief	    Control wakeup pin status.
 * @details     
 * @param[in]   EXTI_WAKEUP : 
 *  @arg\b      DISABLE : Disable key wakeup function.
 *  @arg\b      ENABLE  : Enable key wakeup function.
 * @exception   No
 * @note        
 *******************************************************************************
 */
void API_KB_ExternalWakeup_Cmd( FunctionalState EXTI_WAKEUP)
{
    
    if( EXTI_WAKEUP == ENABLE)
    {
        //===============================================================
        //Enable Keyboard Row wakeup (EXIC Interrupt)
        GPIO_ClearPortBit( KB_SCAN_COLUMN0, KB_SCAN_COLUMN0_MSK);
        GPIO_ClearPortBit( KB_SCAN_COLUMN1, KB_SCAN_COLUMN1_MSK);
        GPIO_ClearPortBit( KB_SCAN_COLUMN2, KB_SCAN_COLUMN2_MSK);

        
        
        EXIC_ClearPxTriggerEventFlag(KB_ROW,(EXIC_PX_PIN0 | EXIC_PX_PIN1 | EXIC_PX_PIN2 | EXIC_PX_PIN3 | EXIC_PX_PIN7 | \
                                             EXIC_PX_PIN8 | EXIC_PX_PIN9 | EXIC_PX_PIN10| EXIC_PX_PIN11));
        
        EXIC_ClearPxTriggerEventFlag(KB_ROW1,(EXIC_PX_PIN14 | EXIC_PX_PIN15));
        

        NVIC_EnableIRQ(KB_SCAN_ROW0_IRQ);
        NVIC_EnableIRQ(KB_SCAN_ROW1_IRQ);
        //==============================================================
        //Enable The Other Peripherals Interrupt
        
        //To do......
    }
    else
    {
        //===============================================================
        //Disable Keyboard Row wakeup (EXIC Interrupt)
        NVIC_DisableIRQ(KB_SCAN_ROW0_IRQ);
        NVIC_DisableIRQ(KB_SCAN_ROW1_IRQ);
        
        GPIO_SetPortBit( KB_SCAN_COLUMN0, KB_SCAN_COLUMN0_MSK);
        GPIO_SetPortBit( KB_SCAN_COLUMN1, KB_SCAN_COLUMN1_MSK);
        GPIO_SetPortBit( KB_SCAN_COLUMN2, KB_SCAN_COLUMN2_MSK);
        
        //==============================================================
        //Disable The Other Peripherals Interrupt
        
        //To do......
    }
}
/**
 *******************************************************************************
 * @brief	    KEYBOARD software control parameter initial.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
void API_KB_Parameter_DeInit(void)
{
    uint8_t KB_Parameter_DeInitTmp;
    
    KB.STDKey_Protocol        = 1;    
    KB.STDKey_Busy            = CLR;
    KB.STDKey_SendFlag        = CLR;
                              
    KB.GhostStatus            = KB_GHOST_NONE;
    
    for(KB_Parameter_DeInitTmp=0;KB_Parameter_DeInitTmp<KB_SCAN_COLUMN;KB_Parameter_DeInitTmp++)
    {
        KB.GhostDebounce[KB_Parameter_DeInitTmp] = 0;
    }
    
    KB.MKey_Busy              = CLR;
    KB.MKey_SendFlag          = CLR;
    
    KB.Scan_Count_BuffOut     = 0;
    KB.Scan_Count_CheckMatrix = 0;
    
    memset( KB.Scan_Buffer_Matrix, 0 , KB_SCAN_COLUMN);
    memset( KB.Scan_Buffer_Matrix_Address, 0 , Key_Record_MAX);
    memset( KB.Scan_Buffer_Matrix_Flag, 0 , Key_Record_MAX);
}
/**
 *******************************************************************************
 * @brief	    KEYBOARD Relationship Control initial.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
void API_KB_Init(void)
{
    PIN_InitTypeDef  KB_GPIOX;
    EXIC_TRGSTypeDef KB_EXIC_TRGS;
    
    //====================================================================
    //Disable KB Row pin interrupt.
    NVIC_DisableIRQ(KB_SCAN_ROW0_IRQ);
    
    //====================================================================
    //GPIO Initial.
    //--------------------------------------------------------------------
    //Scan column & Row
    KB_GPIOX.PINX_Pin                = (PX_Pin_7 | PX_Pin_9 | PX_Pin_10 | PX_Pin_11 | PX_Pin_12 | PX_Pin_13 | PX_Pin_14 | PX_Pin_15);
    KB_GPIOX.PINX_Mode               = PINX_Mode_OpenDrain_O;
    KB_GPIOX.PINX_PUResistant        = PINX_PUResistant_Enable;
    KB_GPIOX.PINX_Speed              = PINX_Speed_Low;
    KB_GPIOX.PINX_Inverse            = PINX_Inverse_Disable;
    KB_GPIOX.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    KB_GPIOX.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    KB_GPIOX.PINX_Alternate_Function = 0;                          
    GPIO_PortMode_Config(IOMA,&KB_GPIOX);
    
    KB_GPIOX.PINX_Pin                = (PX_Pin_14 | PX_Pin_15);
    GPIO_PortMode_Config(IOMB,&KB_GPIOX);
    
    KB_GPIOX.PINX_Pin               = (PX_Pin_0 | PX_Pin_1 | PX_Pin_2 | PX_Pin_3 | PX_Pin_7 | PX_Pin_8 | PX_Pin_9 | PX_Pin_10 | PX_Pin_11 |
                                       PX_Pin_12| PX_Pin_13| PX_Pin_14);
    GPIO_PortMode_Config(IOMC,&KB_GPIOX);
    

    KB_GPIOX.PINX_Pin               = (PX_Pin_0 );                 
    GPIO_PortMode_Config(IOMD,&KB_GPIOX);
    
    GPIOA->SC.H[0] = KB_SCAN_COLUMN0_MSK;
    GPIOD->SC.H[0] = KB_SCAN_COLUMN1_MSK;
    GPIOC->SC.H[0] = ( KB_SCAN_ROW0_MSK | KB_SCAN_COLUMN2_MSK);
    GPIOB->SC.H[0] = KB_SCAN_ROW1_MSK;
    
    //--------------------------------------------------------------------
    // Single Color LED Control Pin 
    KB_GPIOX.PINX_Pin                = (PX_Pin_2 | PX_Pin_5 | PX_Pin_6 );
    KB_GPIOX.PINX_Mode               = PINX_Mode_PushPull_O;
    KB_GPIOX.PINX_PUResistant        = PINX_PUResistant_Enable;
    KB_GPIOX.PINX_Speed              = PINX_Speed_Low;
    KB_GPIOX.PINX_Inverse            = PINX_Inverse_Disable;
    KB_GPIOX.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    KB_GPIOX.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    KB_GPIOX.PINX_Alternate_Function = 0;                          
    GPIO_PortMode_Config(IOMA,&KB_GPIOX);
    
    //====================================================================
    //KB Row pin interrupt initial (EXIC initial). 
    
    EXIC_PxTriggerOrMask_Select( KB_ROW, KB_SCAN_ROW0_MSK);
    EXIC_PxTriggerITEA_Cmd( KB_ROW_IT,ENABLE);

    KB_EXIC_TRGS.EXIC_Pin = ( EXIC_TRGS_PIN0 | EXIC_TRGS_PIN1 | EXIC_TRGS_PIN2 | EXIC_TRGS_PIN3 | EXIC_TRGS_PIN7 |  \
                              EXIC_TRGS_PIN8 | EXIC_TRGS_PIN9 | EXIC_TRGS_PIN10 | EXIC_TRGS_PIN11);
    KB_EXIC_TRGS.EXIC_TRGS_Mode = Dual_edge;
    
    EXIC_PxTriggerMode_Select(KB_ROW,&KB_EXIC_TRGS);
    
    
    EXIC_PxTriggerOrMask_Select( KB_ROW1, KB_SCAN_ROW0_MSK);
    EXIC_PxTriggerITEA_Cmd( KB_ROW1_IT,ENABLE); 
    
    KB_EXIC_TRGS.EXIC_Pin = ( EXIC_TRGS_PIN14 | EXIC_TRGS_PIN15);
    EXIC_PxTriggerMode_Select(KB_ROW1,&KB_EXIC_TRGS);
    

    //====================================================================
    //Delay initial ( Use URT Timeouttimer )
    URT_TimeoutTimerClockSource_Select( KB_DELAY_TM , URT_TMOCLK_CK_URTX);
    URT_TimeoutMode_Select( KB_DELAY_TM , URT_TMOMDS_General);
    URT_TimeroutTimer_Cmd( KB_DELAY_TM , DISABLE);
    
    //====================================================================
    //Keyboard control parameter initial
    API_KB_Parameter_DeInit();
    
}
/**
 *******************************************************************************
 * @brief	    Control Cap / NumLock / ScrollLock LED status.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
void API_KB_Update_LEDStatus(void)
{
    KB_LED_Caps_Status( KB.LED_Status.MBIT.Caps);
    KB_LED_NumLock_Status( KB.LED_Status.MBIT.NumLock);
    KB_LED_ScrollLock_Status( KB.LED_Status.MBIT.ScrollLock);
}

/**
 *******************************************************************************
 * @brief	    Clear status of Key record. 
 * @details        
 * @exception   No
 * @note        
 *******************************************************************************
 */
void API_KB_ClearKeyRecord(void)
{
    KB.Scan_Buffer_Matrix_Address[ KB.Tmp_Index ] = 0;
    KB.Scan_Buffer_Matrix_Flag[ KB.Tmp_Index]     = 0;
}
/**
 *******************************************************************************
 * @brief	    Record the key code already send.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
void API_KB_RecordKeySend(void)
{
    KB.Scan_Buffer_Matrix_Flag[ KB.Tmp_Index]    |= KD_SCAN_Code_Update;                    /*!< Record the key already send.*/
}
/**
 *******************************************************************************
 * @brief	    Keyboard main function.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
void API_KB_Main(void)
{
    uint32_t KB_Main_Tmp;
    

    KB_Main_Tmp = ( Ep0.USBStatus & USB_STATUS_BUS_MASK);
    
    if(KB_Main_Tmp!=0)
    {
        switch( KB_Main_Tmp)
        {
            //============================================================================================
            // During handling the other functions USB bus happen suspend status. 
            case USB_STATUS_BUS_SUSPEND:
                                                                   Ep0.USBStatus = Ep0.USBStatus & (uint32_t)(~USB_STATUS_BUS_SUSPEND);
                                                                   //-------------------------------------------------------------------------
                                                                   //If host allow remote wakeup enable the other external wakeup signal.
                                                                   if(( Ep0.USBStatus & USB_STATUS_RWEN_MASK) == USB_STATUS_RWEN_ENABLE)
                                                                   {
                                                                       API_KB_ExternalWakeup_Cmd( ENABLE);
                                                                   }
																                                   //-------------------------------------------------------------------------
                                                                   //Disable system timebase timer to count.
                                                                   TM_Timer_Cmd(TM10 , DISABLE);
																   
                                                                   //-------------------------------------------------------------------------
                                                                   //Disable RGB 
                                                                   #if MG32_USBD_KEYBOARD_RGB_EN != API_RGB_DISABLE
                                                                       API_AllRGB_OFF();
                                                                   #endif
                                                                   
                                                                   API_KB_LED_OFF();
                                                                   
                                                                   USB_IT_Config( USB_IT_BUS_RWKF , ENABLE);               /*!< Enable USB Bus event wakeup interrupt in STOP mode.*/ 
                                                                   
                                                                   STOP_WFI();
                                                                   
                                                                   //-------------------------------------------------------------------------
                                                                   //Enable RGB
                                                                   #if MG32_USBD_KEYBOARD_RGB_EN != API_RGB_DISABLE
                                                                       API_RGB_CTR.RGB_LINE_ON         = 0;
                                                                   #endif
																                                   //-------------------------------------------------------------------------
                                                                   //Enable system timebase timer
                                                                   TM_ClearFlag(TM10 , TMx_TOF);
                                                                   TM_Timer_Cmd(TM10, ENABLE);
                                                                   break;
            //============================================================================================
            //Detect USB Bus no supsend in STOP mode.            
            case USB_STATUS_BUS_BUSEVENT_WAKEUP:
                                                                   Ep0.USBStatus = Ep0.USBStatus & (uint32_t)(~USB_STATUS_BUS_BUSEVENT_WAKEUP);
            
                                                                   // To do......
                                                                   break;
            //============================================================================================
            //During handling the other functions extern wakeup signal happen.
            case USB_STATUS_BUS_EXTIEVENT_WAKEUP:
                                                                   Ep0.USBStatus = Ep0.USBStatus & (uint32_t)(~USB_STATUS_BUS_EXTIEVENT_WAKEUP);
                                                                   //-------------------------------------------------------------------------
                                                                   //If host allow remote wakeup send remote wakeup signal to host.
                                                                   USB_TriggerRemoteWakeup();
                                                                   //-------------------------------------------------------------------------
                                                                   //Disable external wakeup signal.
                                                                   API_KB_ExternalWakeup_Cmd( DISABLE);
                                                                   
                                                                   //-------------------------------------------------------------------------
                                                                   //Enable system timebase timer
                                                                   TM_ClearFlag(TM10 , TMx_TOF);
                                                                   TM_Timer_Cmd(TM10, ENABLE);                                                           
            
            
                                                                   break;                                                       
            //============================================================================================
            //During handling the other functions USB bus happen suspend and resume status.
            case ( USB_STATUS_BUS_SUSPEND | USB_STATUS_BUS_RESUME):
                                                                   Ep0.USBStatus = Ep0.USBStatus & (uint32_t)(~USB_STATUS_BUS_SUSPEND); 
                                                                   //-------------------------------------------------------------------------
                                                                   //Disable external wakeup signal.
                                                                   API_KB_ExternalWakeup_Cmd( DISABLE);
                                                                   
                                                                   //-------------------------------------------------------------------------
                                                                   //Enable system timebase timer
                                                                   TM_ClearFlag(TM10 , TMx_TOF);
                                                                   TM_Timer_Cmd(TM10, ENABLE); 
            
                                                                   //To do......
            
            
                                                                   break;
            //============================================================================================
            //During handling the other function USB bus happen resume status.
            case (USB_STATUS_BUS_BUSEVENT_WAKEUP | USB_STATUS_BUS_RESUME):
            case (USB_STATUS_BUS_RESUME):
                                                                          Ep0.USBStatus = Ep0.USBStatus & (uint32_t)(~(USB_STATUS_BUS_BUSEVENT_WAKEUP | USB_STATUS_BUS_RESUME));
                                                                          //-------------------------------------------------------------------------
                                                                          //Disable external wakeup signal.
                                                                          API_KB_ExternalWakeup_Cmd( DISABLE);
                                                                          
                                                                          //-------------------------------------------------------------------------
                                                                          //Enable system timebase timer
                                                                          TM_ClearFlag(TM10 , TMx_TOF);
                                                                          TM_Timer_Cmd(TM10, ENABLE);
                                                                          
                                                                          //To do......
                                                                          break;
            
            //============================================================================================
            case (USB_STATUS_BUS_BUSEVENT_WAKEUP | USB_STATUS_BUS_RESET):
            case USB_STATUS_BUS_RESET:
                                                                          Ep0.USBStatus = Ep0.USBStatus & (uint32_t)(~(USB_STATUS_BUS_BUSEVENT_WAKEUP | USB_STATUS_BUS_RESET));
                                                                          // To do...
                                                                          
                                                                          break;
            default:                                                      
                                                                          // To do...
                                                                          
                                                                          break;
        }
        

        
        
        
        Ep0.USBStatus = Ep0.USBStatus & (~KB_Main_Tmp);
    }
    //======================================================================================
    //1. Need min about 520us in 24MHz
    else if( ((Ep0.USBStatus & USB_STATUS_EMULATION_MASK) == USB_STATUS_EMULATION_OK) && KB.Scan_Flag_Start == 1)
    {
        //--------------------------------------
        //Clear Scan flag. 
        KB.Scan_Flag_Start = 0;
        //--------------------------------------
        //Scan Key status
        API_KB_ScanKeyStatus();          
        //--------------------------------------
        //According to Scan result to handle. 
        API_KB_Keyboard_Function();              
    }
}
/**
 *******************************************************************************
 * @brief	    Close Cap / NumLock / ScrollLock LED.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_LED_OFF(void)
{
    KB_LED_Caps       = LED_OFF;
    KB_LED_NumLock    = LED_OFF;
    KB_LED_ScrollLock = LED_OFF;
} 
/**
 *******************************************************************************
 * @brief	    Scan the column status.
 * @details     
 * @param[in]   Scan_Index : Now Scan line.
 * @return      Scan Result.
 * @exception   No
 * @note        
 *******************************************************************************
 */
static uint32_t API_KB_Scaning( uint8_t Scan_Index)
{
             uint32_t KB_SCANTmp = 0;
    volatile uint32_t KB_SCANDebounce;
    
    
    //====================================================================
    //Start Scan the column.
    GPIO_SetClearPortBit( KB_SCAN_COLUMN0 , KeyScan1_Table[Scan_Index][0] , KeyScan0_Table[Scan_Index][0]);
    GPIO_SetClearPortBit( KB_SCAN_COLUMN1 , KeyScan1_Table[Scan_Index][1] , KeyScan0_Table[Scan_Index][1]);
    GPIO_SetClearPortBit( KB_SCAN_COLUMN2 , KeyScan1_Table[Scan_Index][2] , KeyScan0_Table[Scan_Index][2]);
    
    KB_Delay(KB_DELAY_5US);

    for( KB_SCANDebounce = 0; KB_SCANDebounce<100;KB_SCANDebounce++);
    
    //====================================================================
    //Read Row status.
    KB_SCANTmp = (( GPIO_ReadPort( KB_SCAN_ROW0) & KB_SCAN_ROW0_MSK) | (( GPIO_ReadPort( KB_SCAN_ROW1) & KB_SCAN_ROW1_MSK) >> KB_SCAN_ROW1_SHIFT));
    KB_SCANTmp = ((~KB_SCANTmp) & KB_SCAN_ROW_MSK);
    
    //====================================================================
    //End Scan the column.
    GPIO_SetPortBit(KB_SCAN_COLUMN0,KB_SCAN_COLUMN0_MSK);
    GPIO_SetPortBit(KB_SCAN_COLUMN1,KB_SCAN_COLUMN1_MSK);
    GPIO_SetPortBit(KB_SCAN_COLUMN2,KB_SCAN_COLUMN2_MSK);                                   
    
    return( KB_SCANTmp);
    
} 
/**
 *******************************************************************************
 * @brief	    Scan all key status.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_ScanKeyStatus(void)
{
    KB.Scan_Column = 0;

    do{
        KB.Scan_Buffer_Matrix[ KB.Scan_Column] = (uint16_t)API_KB_Scaning( KB.Scan_Column);
        KB.Scan_Column = KB.Scan_Column + 1;
        
    }while( KB.Scan_Column != KB_SCAN_COLUMN);
}

/**
 *******************************************************************************
 * @brief	    Check ghost Key status.
 * @details     Check ghost key whether exist or not . 
 *      \n      If ghost key exist to check happen in which column.
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static FlagStatus API_KB_CheckColumnGhostKey( uint8_t CKGhost_Column)
{
    #if MG32_USBD_KEYBOARD_GHOSTKEY_EN == 1
        uint32_t  KB_CKGhost_CompareBit;        
        uint32_t  KB_CKGhost_CompareMask;
        uint8_t   KB_CKGhost_CompareTmp;
        uint8_t   KB_CKGhost_ActiveCnt;
    
        KB_CKGhost_CompareBit  = 0x00000001;
        KB_CKGhost_CompareMask = KB.Scan_Buffer_Matrix[ CKGhost_Column ];    
        KB_CKGhost_ActiveCnt   = 0;    
    
        /*Check how many columns are active.*/     
        while( KB_CKGhost_CompareMask !=0)
        {
            if( KB_CKGhost_CompareMask & KB_CKGhost_CompareBit)
            {
                KB_CKGhost_ActiveCnt   = KB_CKGhost_ActiveCnt + 1;
                KB_CKGhost_CompareMask = KB_CKGhost_CompareMask & (~KB_CKGhost_CompareBit);
            }
            KB_CKGhost_CompareBit = KB_CKGhost_CompareBit << 1; 
        }

        /*No ghosts exist when less than 2 keys in the column are active.*/
        if( KB_CKGhost_ActiveCnt < 2)
        {
            return(CLR);
        }
        /*Check against other columns to see if more than one row matches.*/
        for( KB_CKGhost_CompareTmp = (CKGhost_Column + 1); KB_CKGhost_CompareTmp < (KB_SCAN_COLUMN-1); KB_CKGhost_CompareTmp++)
        {
            if( KB.Scan_Buffer_Matrix[ KB_CKGhost_CompareTmp ] & KB.Scan_Buffer_Matrix[ CKGhost_Column ])
            {
                return(SET);
            }
        }
        return(CLR);
    #else
        return(CLR);
    #endif
}
/**
 *******************************************************************************
 * @brief	    Handle Keyboard status according to Key scan result.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_Keyboard_Function(void)
{
    //======================================
    //Decode Keyboard status.
    API_KB_CheckGhostKey();                     /*!< To Check ScanIN data whether have ghost key or not.*/ 
    API_KB_CheckScanIn();         
    API_KB_CheckUpdate();
    API_KB_TranslateToKeyCode();
    //======================================
    //Update Keyboard data to Host
    API_KB_UpdateStandardKey();                 /*!< Send Normal KEY .*/
    API_KB_UpdateMultiMediaKey();               /*!< Send MultiMedia Key.*/

}
/**
 *******************************************************************************
 * @brief	    Translate to key code data package.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_TranslateToKeyCode(void)
{
    #if MG32_USBD_KEYBOARD_RGB_EN != API_RGB_DISABLE
        uint8_t API_KB_TranslateToKeyCodeTmp;
    #endif
    
    for( KB.Tmp_Index = 0; KB.Tmp_Index < Key_Record_MAX; KB.Tmp_Index++)
    {
        KB.Tmp_Addr = KB.Scan_Buffer_Matrix_Address[KB.Tmp_Index];
        KB.Tmp_Flag = KB.Scan_Buffer_Matrix_Flag[KB.Tmp_Index];
        
        #if MG32_USBD_KEYBOARD_RGB_EN != API_RGB_DISABLE
            API_KB_TranslateToKeyCodeTmp = 0;
        #endif
        
        if( KB.Tmp_Flag !=0)
        {
            switch(( KB.Tmp_Flag & (( KB_SCAN_MAKE_CONFIRM | KB_SCAN_BREAK_CONFIRM | KD_SCAN_Code_Update))))
            {
                case (KB_SCAN_MAKE_CONFIRM):
                case (KB_SCAN_MAKE_CONFIRM | KB_SCAN_BREAK_CONFIRM | KD_SCAN_Code_Update):
                                                                                          API_KB_TranslateToKeyCode_Flow();
                                                                                          #if MG32_USBD_KEYBOARD_RGB_EN != API_RGB_DISABLE
                                                                                              API_KB_TranslateToKeyCodeTmp = 1;
                                                                                          #endif
                                                                                          break;
                case (KB_SCAN_MAKE_CONFIRM | KB_SCAN_BREAK_CONFIRM):
                                                                                          API_KB_ClearKeyRecord();
                                                                                          #if MG32_USBD_KEYBOARD_RGB_EN != API_RGB_DISABLE
                                                                                              API_KB_TranslateToKeyCodeTmp = 1;
                                                                                          #endif
                                                                                          break;
                default:
                                                                                          break;
            }
        }
        
        #if MG32_USBD_KEYBOARD_RGB_EN != API_RGB_DISABLE
            if(API_KB_TranslateToKeyCodeTmp==1)
            {
                if( KB.Tmp_Flag & KB_SCAN_BREAK_CONFIRM)
                {
                    API_RGB_CTR.KB_Map_RGB_pBuf[API_KB_ATable[KB.Tmp_Addr]] &= (~0x80000000);
                    API_RGB_CTR.KB_Map_RGB_pBuf[API_KB_ATable[KB.Tmp_Addr]] |= 0x40000000; 
                }
                else
                {
                    API_RGB_CTR.KB_Map_RGB_pBuf[API_KB_ATable[KB.Tmp_Addr]] |= 0x80008000;
                }
            }
        #endif
    }
}
/**
 *******************************************************************************
 * @brief	    According to species classify Key code. 
 * @details     
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_TranslateToKeyCode_Flow(void)
{
    KB.Tmp_Code       = Default_KeyCode_Table[KB.Tmp_Addr];
    
    //====================================================================================
    //Standard key except for modify byte.
    if( KB.Tmp_Code > 0x03 && KB.Tmp_Code < 0x92)
    {
        API_KB_TransferSTDNormalCode();
    }
    //====================================================================================
    //Modify of Standard key.
    else if(( KB.Tmp_Code > 0xDF) && ( KB.Tmp_Code < 0xE8))
    {
        API_KB_Transfer_STDModifyCode();
    }
    //====================================================================================
    //Multimedia key.
    else if(( KB.Tmp_Code > 0x9F) && ( KB.Tmp_Code < 0xB4))
    {
        API_KB_TransferMultiMediaCode();
    }
    //====================================================================================
    //RGB Mode change
    #if MG32_USBD_KEYBOARD_RGB_EN != API_RGB_DISABLE
        else if((KB.Tmp_Code > 0xEF) && (KB.Tmp_Code < 0xF4))
        {
            API_RGB_KBMain();
        }        
    #endif
    //====================================================================================
    //Undefine.
    else
    {
        API_KB_ClearKeyRecord();
    }
}
/**
 *******************************************************************************
 * @brief	    To combinate modify byte of standard key data according scan result.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_Transfer_STDModifyCode(void)
{
    uint8_t KB_TRASTDKEY_Tmp = 0x01;
    
    
    KB_TRASTDKEY_Tmp = (uint8_t)(KB_TRASTDKEY_Tmp << (KB.Tmp_Code & 0x0F));                         
    
    
    if( KB.Tmp_Flag & KB_SCAN_BREAK_CONFIRM)
    {
        KB.STDKey_ToHostBuffer[KB_STD_MODIFY]   &= (~KB_TRASTDKEY_Tmp);
        API_KB_ClearKeyRecord();                                                    /*!< Clear the key status in tmporary buffer.*/
        KB.STDKey_SendFlag                       = 1;                                          
    }
    else
    {
        KB.STDKey_ToHostBuffer[KB_STD_MODIFY]   |= (KB_TRASTDKEY_Tmp);
        KB.STDKey_SendFlag                       = 1;
        API_KB_RecordKeySend();                                                     /*!< Record the key already send.*/
    }
}
/**
 *******************************************************************************
 * @brief	    To combinate multimedia data according scan result.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_TransferMultiMediaCode(void)
{    
    uint32_t KB_TRAMKEY_Tmp = 0x00000001;
    
    KB_TRAMKEY_Tmp = (KB_TRAMKEY_Tmp << (KB.Tmp_Code &  0x1F));
    
    
    if( KB.Tmp_Flag & KB_SCAN_BREAK_CONFIRM)
    {
        KB.MKey_ToHostBuffer[1] &=  (~(KB_TRAMKEY_Tmp & 0x000000FF));
        KB.MKey_ToHostBuffer[2] &=  (~((KB_TRAMKEY_Tmp & 0x0000FF00)>>8));
        KB.MKey_ToHostBuffer[3] &=  (~((KB_TRAMKEY_Tmp & 0x00FF0000)>>16));
        KB.MKey_SendFlag         =  1;
        
        API_KB_ClearKeyRecord();                                                     /*!< Clear the key status in tmporary buffer.*/  
    }
    else
    {
        KB.MKey_ToHostBuffer[1] |=  ((KB_TRAMKEY_Tmp & 0x000000FF));
        KB.MKey_ToHostBuffer[2] |=  (((KB_TRAMKEY_Tmp & 0x0000FF00)>>8));
        KB.MKey_ToHostBuffer[3] |=  (((KB_TRAMKEY_Tmp & 0x00FF0000)>>16));
        KB.MKey_SendFlag         =  1;
        
        API_KB_RecordKeySend();                                                      /*!< Record the key already send.*/                            
    }
}
/**
 *******************************************************************************
 * @brief	    To combinate multimedia data according scan result.
 * @details     The function no include modify byte of standard key.
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_TransferSTDNormalCode(void)
{
    uint8_t KB_TraNKeyCode_Tmp;
    uint8_t KB_TraNKeyCode_Tmp2;
    
    
    if( KB.Tmp_Flag & KB_SCAN_BREAK_CONFIRM)
    {
        for( KB_TraNKeyCode_Tmp = KB_STD_NORMAL; KB_TraNKeyCode_Tmp < KB_STDKEY_DATA_SIZE; KB_TraNKeyCode_Tmp ++)
        {
            if( KB.STDKey_ToHostBuffer[ KB_TraNKeyCode_Tmp] == KB.Tmp_Code)
            {
                for( KB_TraNKeyCode_Tmp2 = KB_TraNKeyCode_Tmp; KB_TraNKeyCode_Tmp2 < (KB_STDKEY_DATA_SIZE - 1); KB_TraNKeyCode_Tmp2++)
                {
                    KB.STDKey_ToHostBuffer[ KB_TraNKeyCode_Tmp2] = KB.STDKey_ToHostBuffer[ KB_TraNKeyCode_Tmp2 + 1];
                }
                KB.STDKey_ToHostBuffer[(KB_STDKEY_DATA_SIZE-1)] = 0;
                KB.STDKey_SendFlag = 1;
                
                API_KB_ClearKeyRecord();
                return;
            }
        }
    }
    else
    {
        for( KB_TraNKeyCode_Tmp = KB_STD_NORMAL; KB_TraNKeyCode_Tmp < KB_STDKEY_DATA_SIZE; KB_TraNKeyCode_Tmp ++)
        {
            if( KB.STDKey_ToHostBuffer[KB_TraNKeyCode_Tmp] == KB.Tmp_Code)
            {
                API_KB_RecordKeySend();
                return;
            }
            else if( KB.STDKey_ToHostBuffer[KB_TraNKeyCode_Tmp ] == 0)
            {
                KB.STDKey_ToHostBuffer[KB_TraNKeyCode_Tmp] = KB.Tmp_Code;   
                KB.STDKey_SendFlag = 1;
                API_KB_RecordKeySend();
                return;
            }
        }
    }
}
/**
 *******************************************************************************
 * @brief	    Check status of tmporary buffer.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_CheckUpdate(void)
{
    uint8_t KB_CKUP_Tmp;
    uint8_t KB_CKUP_Status;
    
    for( KB_CKUP_Tmp = 0; KB_CKUP_Tmp < Key_Record_MAX; KB_CKUP_Tmp++)
    {
        KB_CKUP_Status = KB.Scan_Buffer_Matrix_Flag[ KB_CKUP_Tmp];
        
        switch( KB_CKUP_Status & KB_SCAN_MAKE_STATUS_MASK )
        {
            case ( KB_SCAN_MAKE_NOW | KB_SCAN_MAKE_CONFIRM):
                                                            KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp] &= (~KB_SCAN_MAKE_NOW);
                                                            KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp] &= (~KB_SCAN_MAKE_COUNT_MASK);
                                                            break;
            case ( KB_SCAN_MAKE_NOW):
                                                            KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp] &= (~KB_SCAN_MAKE_NOW);
                                                            
                                                            if( (KB_CKUP_Status & KB_SCAN_MAKE_COUNT_MASK) > KB_MAKE_DELAY_TIME)                               /*!< Check make debounce.*/
                                                            {
                                                                KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp] |= KB_SCAN_MAKE_CONFIRM;                               /*!< Confirm the key status is make.*/
                                                                KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp] &= (~KB_SCAN_MAKE_COUNT_MASK);
                                                            }
                                                            else
                                                            {
                                                                KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp] ++;
                                                            }
                                                            break;
            case ( KB_SCAN_MAKE_CONFIRM) :
                                                            if( KB_CKUP_Status & KB_SCAN_BREAK_CONFIRM)                                                         
                                                            {
                                                                break;
                                                            }
                                                            else if( ( KB_CKUP_Status & KB_SCAN_MAKE_COUNT_MASK) > KB_BREAK_DELAY_TIME)                         
                                                            {
                                                                KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp] |= KB_SCAN_BREAK_CONFIRM;
                                                                KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp] &= (~KB_SCAN_MAKE_COUNT_MASK);
                                                            }
                                                            else
                                                            {
                                                                KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp] ++;
                                                            }
                                                            break;
            case 0:
            default:
                                                            KB.Scan_Buffer_Matrix_Address[KB_CKUP_Tmp] = 0;
                                                            KB.Scan_Buffer_Matrix_Flag[KB_CKUP_Tmp]    = 0;
                                                            break;                
        }
    }
}
/**
 *******************************************************************************
 * @brief	    Send multimedia key code to Host.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_UpdateMultiMediaKey(void)
{
    //==============================================================
    // Now in BIOS 
    if( KB.STDKey_Protocol == 0)
    {
        return;
    }
    //==============================================================
    //Ghost key happen.
    if( KB.GhostStatus != KB_GHOST_NONE)
    {
        return;
    }
    //==============================================================
    //Previous multiMedia key data no send.
    if( KB.MKey_Busy == SET)
    {
        return;
    }
    
    //==============================================================
    //Send multimedia key code to Host if there is new key code update.
    if( KB.MKey_SendFlag == SET)                                                                              
    {
        KB.MKey_Busy     = SET;
        KB.MKey_SendFlag = CLR;
        
        KB.MKey_ToHostBuffer[0] = KB_FUNHID_ID_FKB;
        
        API_USBD_WriteEndpointData( KB_MULTIMEDIA_KEY_EP , &KB.MKey_ToHostBuffer[0], 0 , KB_MKEY_DATA_SIZE );
        USB_SetEndpointTXSize( KB_MULTIMEDIA_KEY_EP , KB_MKEY_DATA_SIZE);  
        USB_SetEndpointStatus( KB_MULTIMEDIA_KEY_EP , EP_TX_VALID); 
    }
}
/**
 *******************************************************************************
 * @brief	    Send standard key code to Host
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_UpdateStandardKey(void)
{
    //==============================================================
    //Previous standard key data no send.
    if( KB.STDKey_Busy == SET)
    {
        return;
    }
    
    switch( KB.GhostStatus)
    {
        //==========================================================
        //Send ghost key to host if ghost key not send.
        case KB_GHOST_CONFIRM:
                                                 KB.STDKey_Busy = SET;
                                                 KB.GhostStatus |= KB_GHOST_SEND;
                                                 
                                                 API_USBD_WriteEndpointConstData( KB_STDKEY_EP , 0x00 , 0 , 2);
                                                 API_USBD_WriteEndpointConstData( KB_STDKEY_EP , 0x01 , 2 , 6);
                                                 
                                                 USB_SetEndpointTXSize( KB_STDKEY_EP , KB_STDKEY_DATA_SIZE);  
                                                 USB_SetEndpointStatus( KB_STDKEY_EP , EP_TX_VALID);
                                                 break;
        //===========================================================
        //Ghost key already send and ghost key status no end.
        case (KB_GHOST_CONFIRM | KB_GHOST_SEND):
                                                 return;
        //===========================================================
        //Send standard key to host.
        case KB_GHOST_NONE:                      
        default:                                 
                                                 if( KB.STDKey_SendFlag == SET)
                                                 {
                                                     KB.STDKey_Busy     = SET;
                                                     KB.STDKey_SendFlag = CLR;
                                                     API_USBD_WriteEndpointData( KB_STDKEY_EP , &KB.STDKey_ToHostBuffer[0], 0 , KB_STDKEY_DATA_SIZE);
                                                     USB_SetEndpointTXSize( KB_STDKEY_EP , KB_STDKEY_DATA_SIZE);  
                                                     USB_SetEndpointStatus( KB_STDKEY_EP , EP_TX_VALID); 
                                                     
                                                 }
                                                 break;
    }
}
/**
 *******************************************************************************
 * @brief	    Check keyboard scan result.
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_CheckScanIn(void)
{
    uint8_t KB_CKScanIn_Tmp;

    KB.Scan_Flag_Matrix_Checked   = 0;
    KB.Scan_Flag_Matrix_CheckFull = 0;
    KB.Scan_Count_CheckMatrix     = 0;
    
    for( KB_CKScanIn_Tmp = 0; KB_CKScanIn_Tmp < KB_SCAN_COLUMN; KB_CKScanIn_Tmp++)
    {
        if( KB.Scan_Buffer_Matrix[KB.Scan_Count_BuffOut ]!=0)                                         /*!< Keyboard have any key event happen.*/
        {
            API_KB_CheckScanInMatrix();                                                               /*!< Check keyboard event in whcich { column , row}.*/
            
            if( KB.Scan_Flag_Matrix_Checked == SET)                                                  
            {
                return;
            }
            
        }
        if( KB.Scan_Count_BuffOut > ( KB_SCAN_COLUMN-2))
        {
            KB.Scan_Count_BuffOut = 0;
        }
        else
        {
            KB.Scan_Count_BuffOut++;
        }
    }
    KB.Scan_Count_BuffOut = 0;
}
/**
 *******************************************************************************
 * @brief	    Check event happen in which row  
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_CheckScanInMatrix(void)
{
    uint8_t  KB_CKSCanIn_RowTmp;
    uint32_t KB_CKSCanIn_Cmp = 0x00000001;


    for( KB_CKSCanIn_RowTmp = 0; KB_CKSCanIn_RowTmp < KB_SCAN_ROW ; KB_CKSCanIn_RowTmp++)
    {
        if( KB.Scan_Buffer_Matrix[ KB.Scan_Count_BuffOut] & KB_CKSCanIn_Cmp)                        /*!< the row of Keyboard have key event happen.*/
        {
            KB.Tmp_Addr     = (KB_CKSCanIn_RowTmp * KB_SCAN_COLUMN) + KB.Scan_Count_BuffOut;
            KB.Tmp_Code     = Default_KeyCode_Table[KB.Tmp_Addr];
            
            if( KB.Tmp_Code  !=0)                                                                   /*!< If the key code is significant update the key code to tmporary buffer of send.*/
            {
                API_KB_CheckUpdateKeyMatrix();
                
                if( KB.Scan_Flag_Matrix_Checked == SET)                                             /*!< If tmporary buffer is already full jump away the check flow.*/
                {
                    return;
                }
            }
        }
        KB_CKSCanIn_Cmp = KB_CKSCanIn_Cmp << 1;
    }
}
/**
 *******************************************************************************
 * @brief	    Update key code to tmporary buffer.
 * @details     It check status of tmporary buffer at the same time.
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_CheckUpdateKeyMatrix(void)
{
    uint8_t KB_CK_UpdateTmp;
    
    
    //=====================================================================================
    //Check the code whether already exist in buffer or not.
    for( KB_CK_UpdateTmp = 0; KB_CK_UpdateTmp < Key_Record_MAX; KB_CK_UpdateTmp++)
    {
        if(( KB.Scan_Buffer_Matrix_Flag[ KB_CK_UpdateTmp] !=0) && ( KB.Scan_Buffer_Matrix_Address[ KB_CK_UpdateTmp] == KB.Tmp_Addr))
        {
            KB.Scan_Buffer_Matrix_Flag[KB_CK_UpdateTmp] |=  KB_SCAN_MAKE_NOW;
            
            KB.Scan_Count_CheckMatrix ++;
            
            if( KB.Scan_Count_CheckMatrix > (Key_Record_MAX - 1))                                  /*!< Key event temporary buffer still is full .*/
            {
                KB.Scan_Flag_Matrix_Checked = SET;
            }
            return;
        }
    }
    //=====================================================================================
    //Save the code to the buffer if no ghost key or the buffer no full.
    if(KB.GhostStatus == KB_GHOST_NONE)
    {
        if( KB.Scan_Flag_Matrix_CheckFull == CLR)
        {
            for( KB_CK_UpdateTmp = 0; KB_CK_UpdateTmp < Key_Record_MAX; KB_CK_UpdateTmp++)
            {
                if( KB.Scan_Buffer_Matrix_Flag[ KB_CK_UpdateTmp] == 0)
                {                    
                    KB.Scan_Buffer_Matrix_Address[ KB_CK_UpdateTmp] =  KB.Tmp_Addr;
                    KB.Scan_Buffer_Matrix_Flag[KB_CK_UpdateTmp]     |= KB_SCAN_MAKE_NOW;
                    
                    KB.Scan_Count_CheckMatrix ++;
                    
                    if( KB.Scan_Count_CheckMatrix > ( Key_Record_MAX - 1))
                    {
                        KB.Scan_Flag_Matrix_Checked = SET;   
                    }
                    return;
                }
            }
            KB.Scan_Flag_Matrix_CheckFull = SET;                                                    /*!<Key event temporary buffer is full .*/
        }
    }
}
/**
 *******************************************************************************
 * @brief	    Check Ghost Key flow
 * @details     
 * @return      
 * @exception   No
 * @note        
 *******************************************************************************
 */
static void API_KB_CheckGhostKey(void)
{
    uint8_t  KB_CKGhost_ColumnTmp;
    uint8_t  KB_CKGhost_NoActCntTmp;
    //=============================================================================
    KB_CKGhost_NoActCntTmp = 0;
    
    for( KB_CKGhost_ColumnTmp = 0; KB_CKGhost_ColumnTmp < (KB_SCAN_COLUMN-1);KB_CKGhost_ColumnTmp++)
    {
        if(API_KB_CheckColumnGhostKey(KB_CKGhost_ColumnTmp)==SET)
        {
            /*Ghost status no released.*/
            if( KB.GhostStatus & KB_GHOST_CONFIRM)
            {
                return;
            }
            /*Detect ghost status.*/
            else
            {
                KB.GhostStatus  |= KB_GHOST_CONFIRM;
                KB.GhostDebounce[KB_CKGhost_ColumnTmp] = (KB_BREAK_DELAY_TIME+1);
                return;
            }
        }
        else if(KB.GhostDebounce[KB_CKGhost_ColumnTmp]!=0)
        {
            KB.GhostDebounce[KB_CKGhost_ColumnTmp]  = KB.GhostDebounce[KB_CKGhost_ColumnTmp] - 1;
        }
        else
        {
            KB_CKGhost_NoActCntTmp = KB_CKGhost_NoActCntTmp + 1;
        }
    }
    //=============================================================================
    if(KB_CKGhost_NoActCntTmp==(KB_SCAN_COLUMN-1))
    {
        KB.GhostStatus   = KB_GHOST_NONE;
    }
}







