/**
******************************************************************************************************************************************************************************************
*@file                       user_keyboard.c
*@author         
*@data                       
*@version                    v1.0
*@par Copyright(c):
*
*@par History:
*     version:author,date,desc
*     v1.0   :create this file
*
*******************************************************************************************************************************************************************************************
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "cpu.h"
#include "user_keyboard.h"
#include "cpu_gpio.h"
#include "app_trace.h"

//#define KEYBOARD							((kpc_type_def *)KEYBOARD_BASE) 

typedef struct 
{
    uint32_t gpio_map;
	gpio_type_def *key_high_value;
	gpio_type_def *key_low_value;
    kb_callbcak_t cbk;
}keyboard_env_t;

keyboard_env_t keyboard_env;

void keyboard_init(void)
{
    memset(&keyboard_env, 0, sizeof(keyboard_env_t));
}

static void keyboard_scan_interval_config(kb_scan_interval_t scan_interval)
{
    KEYBOARD->kpc_cfg2 &= 0x0;
    switch(scan_interval)
	{
        case KB_INTERVAL_4MS:
			/// nothing do.
			break;
		case KB_INTERVAL_6MS:
			KEYBOARD->kpc_cfg2 |= 0x01;
			break;
		case KB_INTERVAL_8MS:
			KEYBOARD->kpc_cfg2 |= 0x02;
			break;
		case KB_INTERVAL_12MS:
			KEYBOARD->kpc_cfg2 |= 0x05;
			break;
		case KB_INTERVAL_16MS:
			KEYBOARD->kpc_cfg2 |= 0x06;
			break;
		case KB_INTERVAL_24MS:
			KEYBOARD->kpc_cfg2 |= 0x09;
			break;
		case KB_INTERVAL_32MS:
			KEYBOARD->kpc_cfg2 |= 0x0A;
			break;
		case KB_INTERVAL_48MS:
			KEYBOARD->kpc_cfg2 |= 0x0d;
			break;
		case KB_INTERVAL_64MS:
			KEYBOARD->kpc_cfg2 |= 0x0e;
			break;
		default:
			/// nothong do.
			break;
	}
}
//fix note ²âÊÔ
void keyboard_config(keyboard_param_t *p_conf)
{
    uint8_t i,num = 0;
	uint16_t kpc_cfg1_map = 0;
	for(i=0; i< 32; i++)
	{
        if(p_conf->gpio_map & (0x01<<i))
    	{
    	    
			kpc_cfg1_map |= (0x01<<num);
            num++;
			if(num > 16)
				break;
    	    if(i< 8)
	    	{
	    	    if(keyboard_env.key_low_value == 0)
					keyboard_env.key_low_value = GPIOA;
			}
			else if(i>=8 && i<16)
			{
				if(keyboard_env.key_low_value == NULL)
					keyboard_env.key_low_value = GPIOB;
				
                if((keyboard_env.key_low_value != GPIOB) && (keyboard_env.key_high_value == NULL))
					keyboard_env.key_high_value = GPIOB;
			}
			else if(i>=16 && i<24)
			{
				if(keyboard_env.key_low_value == NULL)
					keyboard_env.key_low_value = GPIOC;
                if((keyboard_env.key_low_value != GPIOC) && (keyboard_env.key_high_value == NULL))
					keyboard_env.key_high_value = GPIOC;
			}
			else
			{
				if(keyboard_env.key_low_value == NULL)
					keyboard_env.key_low_value = GPIOD;
                if((keyboard_env.key_low_value != GPIOD) && (keyboard_env.key_high_value == NULL))
					keyboard_env.key_high_value = GPIOD;
			}

			gpio_init((gpio_pin)i, GPIO_Mode_Input);
			gpio_remap_config((gpio_pin)i,(gpio_remap_type)(GPIO_Remap_KPC_PIO0+num-1));
		}
	}
	keyboard_env.gpio_map = p_conf->gpio_map;
	keyboard_env.cbk = p_conf->cbk;
	KEYBOARD->kpc_cfg1 = kpc_cfg1_map;
	KEYBOARD->kpc_int_ctrl |= KPC_INT_CTL_INT_EN_Mask;
	
	keyboard_scan_interval_config(p_conf->scan_interval);
}

void keyboard_enable_ctrl(functional_state_t new_state)
{
    if(new_state != DISABLE)
	{
        KEYBOARD->kpc_ctrl = KPC_CTRL_KPC_ENABLE_Mask;
	}
	else
	{
        KEYBOARD->kpc_ctrl &= KPC_CTRL_KPC_ENABLE_Mask;
	}
}

bool keyboard_is_working()
{
    return (KEYBOARD->kpc_ctrl & KPC_CTRL_KPC_ENABLE_Mask);
}
static void keyboard_clear_interrupt(void)
{
    KEYBOARD->kpc_stat = 0x01;
}

static uint16_t keyboard_get_data(void)
{
    /// if first row,get data from check gpio IOD. or from check keyboard data register.
    uint16_t volatile data = 0;
    if(keyboard_env.key_low_value)
		data = (keyboard_env.key_low_value->inout_ctrl->IOD>>8 &KEYBOARD->kpc_cfg1);
    //if(keyboard_env.key_high_value)
		//data += (keyboard_env.key_high_value->inout_ctrl->IOD>>8)<<8;

    //if((data & keyboard_env.gpio_map) == keyboard_env.gpio_map)
	if(data == KEYBOARD->kpc_cfg1 & 0xffff)
		data = KEYBOARD->kpc_data&0xffff;
    return data;
}

void Keyboard_IRQHandler(void)
{
	uint16_t kb_data = keyboard_get_data();
	uint16_t kb_io   = KEYBOARD->kpc_cfg1 & 0xffff;
    keyboard_clear_interrupt();

    //dbg_printf("kb ata 0x%x\r\n",kb_data);
	if(keyboard_env.cbk != NULL)
	{
		keyboard_env.cbk((~kb_data)&kb_io);  
	}
}



